注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

BCB-DG's Blog

...

 
 
 

日志

 
 

VNC Cursor  

2007-08-14 11:10:19|  分类: VNC |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
// Add the mouse pointer to the buffer
void
vncDesktop::CaptureMouse(BYTE *scrBuff, UINT scrBuffSize)
{
    POINT CursorPos;
    ICONINFO IconInfo;

    // If the mouse cursor handle is invalid then forget it
    if (m_hcursor == NULL)
        return;

    // Get the cursor position
    if (!GetCursorPos(&CursorPos))
        return;
    //vnclog.Print(LL_INTINFO, VNCLOG("CursorPos %i %i\n"),CursorPos.x, CursorPos.y);
    // Translate position for hotspot
    if (GetIconInfo(m_hcursor, &IconInfo))
    {
        CursorPos.x -= ((int) IconInfo.xHotspot);
        CursorPos.y -= ((int) IconInfo.yHotspot);
        /// Buffer has (0,0) coordinates, Cursor (screencoordinates)
        CursorPos.x -= m_ScreenOffsetx;
        CursorPos.y -= m_ScreenOffsety;
        ///
        if (IconInfo.hbmMask != NULL)
            DeleteObject(IconInfo.hbmMask);
        if (IconInfo.hbmColor != NULL)
            DeleteObject(IconInfo.hbmColor);
    }

    // Select the memory bitmap into the memory DC
    HBITMAP oldbitmap;
    if ((oldbitmap = (HBITMAP) SelectObject(m_hmemdc, m_membitmap)) == NULL)
        return;

    // Draw the cursor
    DrawIconEx(
        m_hmemdc,                                    // handle to device context
        CursorPos.x, CursorPos.y,
        m_hcursor,                                    // handle to icon to draw
        0,0,                                        // width of the icon
        0,                                            // index of frame in animated cursor
        NULL,                                        // handle to background brush
        DI_NORMAL | DI_COMPAT                        // icon-drawing flags
        );

    // Select the old bitmap back into the memory DC
    SelectObject(m_hmemdc, oldbitmap);

    // Save the bounding rectangle
    m_cursorpos.tl = CursorPos;
    m_cursorpos.br = rfb::Point(GetSystemMetrics(SM_CXCURSOR),
        GetSystemMetrics(SM_CYCURSOR)).translate(CursorPos);

    // Clip the bounding rect to the screen
    // Copy the mouse cursor into the screen buffer, if any of it is visible
    m_cursorpos = m_cursorpos.intersect(m_bmrect);
    if (!m_cursorpos.is_empty()) {
        CopyToBuffer(m_cursorpos, scrBuff, scrBuffSize);
    }
}

// CURSOR HANDLING
// Obtain cursor image data in server's local format.
// The length of databuf[] should be at least (width * height * 4).
BOOL
vncDesktop::GetRichCursorData(BYTE *databuf, HCURSOR hcursor, int width, int height)
{
    // Protect the memory bitmap (is it really necessary here?)
    omni_mutex_lock l(m_update_lock);

    // Create bitmap, select it into memory DC
    HBITMAP membitmap = CreateCompatibleBitmap(m_hrootdc, width, height);
    if (membitmap == NULL) {
        return FALSE;
    }
    HBITMAP oldbitmap = (HBITMAP) SelectObject(m_hmemdc, membitmap);
    if (oldbitmap == NULL) {
        DeleteObject(membitmap);
        return FALSE;
    }

    // Draw the cursor
    DrawIconEx(m_hmemdc, 0, 0, hcursor, 0, 0, 0, NULL, DI_IMAGE);
    SelectObject(m_hmemdc, oldbitmap);

    // Prepare BITMAPINFO structure (copy most m_bminfo fields)
    BITMAPINFO *bmi = (BITMAPINFO *)calloc(1, sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD));
    memcpy(bmi, &m_bminfo.bmi, sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD));
    bmi->bmiHeader.biWidth = width;
    bmi->bmiHeader.biHeight = -height;

    // Clear data buffer and extract RGB data
    memset(databuf, 0x00, width * height * 4);
    int lines = GetDIBits(m_hmemdc, membitmap, 0, height, databuf, bmi, DIB_RGB_COLORS);

    // Cleanup
    free(bmi);
    DeleteObject(membitmap);

    return (lines != 0);
}

//  Copyright (C) 2000 Const Kaplinsky. All Rights Reserved.
#include "vncEncoder.h"
#include "vncBuffer.h"
#include "vncDesktop.h"
//
// New code implementing cursor shape updates.
//
BOOL
vncEncoder::IsXCursorSupported()
{
    if (m_use_xcursor) return true;
    if (m_use_richcursor) return true;
    return false;
}
BOOL
vncEncoder::SendEmptyCursorShape(VSocket *outConn)
{
    rfbFramebufferUpdateRectHeader hdr;
    hdr.r.x = Swap16IfLE(0);
    hdr.r.y = Swap16IfLE(0);
    hdr.r.w = Swap16IfLE(0);
    hdr.r.h = Swap16IfLE(0);
    if (m_use_xcursor) {
        hdr.encoding = Swap32IfLE(rfbEncodingXCursor);
    } else {
        hdr.encoding = Swap32IfLE(rfbEncodingRichCursor);
    }

    return outConn->SendExactQueue((char *)&hdr, sizeof(hdr));
}

BOOL
vncEncoder::SendCursorShape(VSocket *outConn, vncDesktop *desktop)
{
    // Make sure the function is used correctly
    if (!m_use_xcursor && !m_use_richcursor)
        return FALSE;

    // Check mouse cursor handle
    HCURSOR hcursor = desktop->GetCursor();
    if (hcursor == NULL) {
        vnclog.Print(LL_INTINFO, VNCLOG("cursor handle is NULL.\n"));
        return FALSE;
    }

    // Get cursor info
    ICONINFO IconInfo;
    if (!GetIconInfo(hcursor, &IconInfo)) {
        vnclog.Print(LL_INTINFO, VNCLOG("GetIconInfo() failed.\n"));
        return FALSE;
    }
    BOOL isColorCursor = FALSE;
    if (IconInfo.hbmColor != NULL) {
        isColorCursor = TRUE;
        DeleteObject(IconInfo.hbmColor);
    }
    if (IconInfo.hbmMask == NULL) {
        vnclog.Print(LL_INTINFO, VNCLOG("cursor bitmap handle is NULL.\n"));
        return FALSE;
    }

    // Check bitmap info for the cursor
    BITMAP bmMask;
    if (!GetObject(IconInfo.hbmMask, sizeof(BITMAP), (LPVOID)&bmMask)) {
        vnclog.Print(LL_INTINFO, VNCLOG("GetObject() for bitmap failed.\n"));
        DeleteObject(IconInfo.hbmMask);
        return FALSE;
    }
    if (bmMask.bmPlanes != 1 || bmMask.bmBitsPixel != 1) {
        vnclog.Print(LL_INTINFO, VNCLOG("incorrect data in cursor bitmap.\n"));
        DeleteObject(IconInfo.hbmMask);
        return FALSE;
    }

    // Get monochrome bitmap data for cursor
    // NOTE: they say we should use GetDIBits() instead of GetBitmapBits().
    BYTE *mbits = new BYTE[bmMask.bmWidthBytes * bmMask.bmHeight];
    if (mbits == NULL)
        return FALSE;

    BOOL success = GetBitmapBits(IconInfo.hbmMask,
                                 bmMask.bmWidthBytes * bmMask.bmHeight, mbits);
    DeleteObject(IconInfo.hbmMask);

    if (!success) {
        vnclog.Print(LL_INTINFO, VNCLOG("GetBitmapBits() failed.\n"));
        delete[] mbits;
        return FALSE;
    }

    // Compute cursor dimensions
    int width = bmMask.bmWidth;
    int height = (isColorCursor) ? bmMask.bmHeight : bmMask.bmHeight/2;

    // Call appropriate routine to send cursor shape update
    if (!isColorCursor && m_use_xcursor) {
        FixCursorMask(mbits, NULL, width, bmMask.bmHeight, bmMask.bmWidthBytes);
        success = SendXCursorShape(outConn, mbits,
                                   IconInfo.xHotspot, IconInfo.yHotspot,
                                   width, height);
    }
    else if (m_use_richcursor) {
        int cbits_size = width * height * 4;
        BYTE *cbits = new BYTE[cbits_size];
        if (cbits == NULL) {
            delete[] mbits;
            return FALSE;
        }
        if (!desktop->GetRichCursorData(cbits, hcursor, width, height)) {
            vnclog.Print(LL_INTINFO, VNCLOG("vncDesktop::GetRichCursorData() failed.\n"));
            delete[] mbits;
            delete[] cbits;
            return FALSE;
        }
        FixCursorMask(mbits, cbits, width, height, bmMask.bmWidthBytes);
        success = SendRichCursorShape(outConn, mbits, cbits,
                                      IconInfo.xHotspot, IconInfo.yHotspot,
                                      width, height);
        delete[] cbits;
    }
    else {
        success = FALSE;    // FIXME: We could convert RichCursor -> XCursor.
    }

    // Cleanup
    delete[] mbits;

    return success;
}

BOOL
vncEncoder::SendXCursorShape(VSocket *outConn, BYTE *mask,
                             int xhot, int yhot, int width, int height)
{
    rfbFramebufferUpdateRectHeader hdr;
    hdr.r.x = Swap16IfLE(xhot);
    hdr.r.y = Swap16IfLE(yhot);
    hdr.r.w = Swap16IfLE(width);
    hdr.r.h = Swap16IfLE(height);
    hdr.encoding = Swap32IfLE(rfbEncodingXCursor);

    BYTE colors[6] = { 0, 0, 0, 0xFF, 0xFF, 0xFF };
    int maskRowSize = (width + 7) / 8;
    int maskSize = maskRowSize * height;

    if ( !outConn->SendExactQueue((char *)&hdr, sizeof(hdr)) ||
         !outConn->SendExactQueue((char *)colors, 6) ||
         !outConn->SendExactQueue((char *)&mask[maskSize], maskSize) ||
         !outConn->SendExactQueue((char *)mask, maskSize) ) {
        return FALSE;
    }
    return TRUE;
}

BOOL
vncEncoder::SendRichCursorShape(VSocket *outConn, BYTE *mbits, BYTE *cbits,
                                int xhot, int yhot, int width, int height)
{
    rfbFramebufferUpdateRectHeader hdr;
    hdr.r.x = Swap16IfLE(xhot);
    hdr.r.y = Swap16IfLE(yhot);
    hdr.r.w = Swap16IfLE(width);
    hdr.r.h = Swap16IfLE(height);
    hdr.encoding = Swap32IfLE(rfbEncodingRichCursor);

    // Cet cursor image in local pixel format
    int srcbuf_rowsize = width * (m_localformat.bitsPerPixel / 8);
    while (srcbuf_rowsize % sizeof(DWORD))
        srcbuf_rowsize++;    // Actually, this should never happen

    // Translate image to client pixel format
    int dstbuf_size = width * height * (m_remoteformat.bitsPerPixel / 8);
    BYTE *dstbuf = new BYTE[dstbuf_size];
    Translate(cbits, dstbuf, width, height, srcbuf_rowsize);

    // Send the data
    int mask_rowsize = (width + 7) / 8;
    int mask_size = mask_rowsize * height;
    if ( !outConn->SendExactQueue((char *)&hdr, sizeof(hdr)) ||
         !outConn->SendExactQueue((char *)dstbuf, dstbuf_size) ||
         !outConn->SendExactQueue((char *)mbits, mask_size) ) {
        delete[] dstbuf;
        return FALSE;
    }
    delete[] dstbuf;
    return TRUE;
}

void
vncEncoder::FixCursorMask(BYTE *mbits, BYTE *cbits,
                          int width, int height, int width_bytes)
{
    int packed_width_bytes = (width + 7) / 8;

    // Pack and invert bitmap data (mbits)
    int x, y;
    for (y = 0; y < height; y++)
        for (x = 0; x < packed_width_bytes; x++)
            mbits[y * packed_width_bytes + x] = ~mbits[y * width_bytes + x];

    // Replace "inverted background" bits with black color to ensure
    // cross-platform interoperability. Not beautiful but necessary code.
    if (cbits == NULL) {
        BYTE m, c;
        height /= 2;
        for (y = 0; y < height; y++) {
            for (x = 0; x < packed_width_bytes; x++) {
                m = mbits[y * packed_width_bytes + x];
                c = mbits[(height + y) * packed_width_bytes + x];
                mbits[y * packed_width_bytes + x] |= ~(m | c);
                mbits[(height + y) * packed_width_bytes + x] |= ~(m | c);
            }
        }
    } else {
        int bytes_pixel = m_localformat.bitsPerPixel / 8;
        int bytes_row = width * bytes_pixel;
        while (bytes_row % sizeof(DWORD))
            bytes_row++;    // Actually, this should never happen

        BYTE bitmask;
        int b1, b2;
        for (y = 0; y < height; y++) {
            bitmask = 0x80;
            for (x = 0; x < width; x++) {
                if ((mbits[y * packed_width_bytes + x / 8] & bitmask) == 0) {
                    for (b1 = 0; b1 < bytes_pixel; b1++) {
                        if (cbits[y * bytes_row + x * bytes_pixel + b1] != 0) {
                            mbits[y * packed_width_bytes + x / 8] ^= bitmask;
                            for (b2 = b1; b2 < bytes_pixel; b2++)
                                cbits[y * bytes_row + x * bytes_pixel + b2] = 0x00;
                            break;
                        }
                    }
                }
                if ((bitmask >>= 1) == 0)
                    bitmask = 0x80;
            }
        }
    }
}

// Translate a rectangle (using arbitrary m_bytesPerRow value,
// always translating from the beginning of the source pixel array)
// NOTE: overloaded function!
inline void
vncEncoder::Translate(BYTE *source, BYTE *dest, int w, int h, int bytesPerRow)
{
    // Call the translation function
    (*m_transfunc) (m_transtable, &m_localformat, &m_transformat,
                    (char *)source, (char *)dest, bytesPerRow, w, h);
}

*****************************************************************************************

// XCursor and RichCursor encodings
// Support for cursor shape updates for ClientConnection class.
#include "stdhdrs.h"
#include "vncviewer.h"
#include "ClientConnection.h"

void ClientConnection::ReadCursorShape(rfbFramebufferUpdateRectHeader *pfburh) {

    vnclog.Print(6, _T("Receiving cursor shape update, cursor %dx%d\n"),
                 (int)pfburh->r.w, (int)pfburh->r.h);

    int bytesPerRow = (pfburh->r.w + 7) / 8;
    int bytesMaskData = bytesPerRow * pfburh->r.h;
    int bytesSourceData =
        pfburh->r.w * pfburh->r.h * (m_myFormat.bitsPerPixel / 8);
    CheckBufferSize(bytesMaskData);

    SoftCursorFree();

    if (pfburh->r.w * pfburh->r.h == 0)
        return;

    // Ignore cursor shape updates if requested by user
    if (m_opts.m_ignoreShapeUpdates) {
        int bytesToSkip = (pfburh->encoding == rfbEncodingXCursor) ?
            (6 + 2 * bytesMaskData) : (bytesSourceData + bytesMaskData);
        CheckBufferSize(bytesToSkip);
        ReadExact(m_netbuf, bytesToSkip);
        return;
    }

    // Read cursor pixel data.
    rcSource = new COLORREF[pfburh->r.w * pfburh->r.h];

    if (pfburh->encoding == rfbEncodingXCursor) {
        CARD8 xcolors[6];
        ReadExact((char *)xcolors, 6);
        COLORREF rcolors[2];
        rcolors[1] = PALETTERGB(xcolors[0], xcolors[1], xcolors[2]);
        rcolors[0] = PALETTERGB(xcolors[3], xcolors[4], xcolors[5]);

        ReadExact(m_netbuf, bytesMaskData);
        int x, y, n, b;
        int i = 0;
        for (y = 0; y < pfburh->r.h; y++) {
            for (x = 0; x < pfburh->r.w / 8; x++) {
                b = m_netbuf[y * bytesPerRow + x];
                for (n = 7; n >= 0; n--)
                    rcSource[i++] = rcolors[b >> n & 1];
            }
            for (n = 7; n >= 8 - pfburh->r.w % 8; n--) {
                rcSource[i++] = rcolors[m_netbuf[y * bytesPerRow + x] >> n & 1];
            }
        }
    } else {
        // rfb.EncodingRichCursor
        CheckBufferSize(bytesSourceData);
        ReadExact(m_netbuf, bytesSourceData);
        SETUP_COLOR_SHORTCUTS;
        char *p = m_netbuf;
        for (int i = 0; i < pfburh->r.w * pfburh->r.h; i++) {
            switch (m_myFormat.bitsPerPixel) {
            case 8:
                rcSource[i] = COLOR_FROM_PIXEL8_ADDRESS(p);
                p++;
                break;
            case 16:
                rcSource[i] = COLOR_FROM_PIXEL16_ADDRESS(p);
                p += 2;
                break;
            case 32:
                rcSource[i] = COLOR_FROM_PIXEL32_ADDRESS(p);
                p += 4;
                break;
            }
        }
    }

    // Read and decode mask data.
    ReadExact(m_netbuf, bytesMaskData);

    rcMask = new bool[pfburh->r.w * pfburh->r.h];

    int x, y, n, b;
    int i = 0;
    for (y = 0; y < pfburh->r.h; y++) {
        for (x = 0; x < pfburh->r.w / 8; x++) {
            b = m_netbuf[y * bytesPerRow + x];
            for (n = 7; n >= 0; n--)
                rcMask[i++] = (b >> n & 1) != 0;
        }
        for (n = 7; n >= 8 - pfburh->r.w % 8; n--) {
            rcMask[i++] = (m_netbuf[y * bytesPerRow + x] >> n & 1) != 0;
        }
    }

    // Set remaining data associated with cursor.
    omni_mutex_lock l(m_cursorMutex);

    rcWidth = pfburh->r.w;
    rcHeight = pfburh->r.h;
    rcHotX = (pfburh->r.x < rcWidth) ? pfburh->r.x : rcWidth - 1;
    rcHotY = (pfburh->r.y < rcHeight) ? pfburh->r.y : rcHeight - 1;

    {
        omni_mutex_lock l(m_bitmapdcMutex);
        ObjectSelector b1(m_hBitmapDC, m_hBitmap);
        PaletteSelector ps1(m_hBitmapDC, m_hPalette);
        m_hSavedAreaDC = CreateCompatibleDC(m_hBitmapDC);
        m_hSavedAreaBitmap =
            CreateCompatibleBitmap(m_hBitmapDC, rcWidth, rcHeight);
    }

    SoftCursorSaveArea();
    SoftCursorDraw();

    rcCursorHidden = false;
    rcLockSet = false;

    prevCursorSet = true;
}

// marscha PointerPos
void ClientConnection::ReadCursorPos(rfbFramebufferUpdateRectHeader *pfburh)
{
    int x = (int)pfburh->r.x;
    if (x >= m_si.framebufferWidth)
        x = m_si.framebufferWidth - 1;
    int y = (int)pfburh->r.y;
    if (y >= m_si.framebufferHeight)
        y = m_si.framebufferHeight - 1;
    //vnclog.Print(2, _T("reading cursor pos (%d, %d)\n"), x, y);
    SoftCursorMove(x, y);
}

// SoftCursorLockArea(). This method should be used to prevent
// collisions between simultaneous framebuffer update operations and
// cursor drawing operations caused by movements of pointing device.
// The parameters denote a rectangle where mouse cursor should not
// be drawn. Every next call to this function expands locked area so
// previous locks remain active.
void ClientConnection::SoftCursorLockArea(int x, int y, int w, int h) {

    omni_mutex_lock l(m_cursorMutex);

    if (!prevCursorSet)
        return;

    if (!rcLockSet) {
        rcLockX = x;
        rcLockY = y;
        rcLockWidth = w;
        rcLockHeight = h;
        rcLockSet = true;
    } else {
        int newX = (x < rcLockX) ? x : rcLockX;
        int newY = (y < rcLockY) ? y : rcLockY;
        rcLockWidth = (x + w > rcLockX + rcLockWidth) ?
            (x + w - newX) : (rcLockX + rcLockWidth - newX);
        rcLockHeight = (y + h > rcLockY + rcLockHeight) ?
            (y + h - newY) : (rcLockY + rcLockHeight - newY);
        rcLockX = newX;
        rcLockY = newY;
    }

    if (!rcCursorHidden && SoftCursorInLockedArea()) {
        SoftCursorRestoreArea();
        rcCursorHidden = true;
    }
}

// SoftCursorUnlockScreen(). This function discards all locks
// performed since previous SoftCursorUnlockScreen() call.
void ClientConnection::SoftCursorUnlockScreen()
{
    omni_mutex_lock l(m_cursorMutex);

    if (!prevCursorSet)
        return;

    if (rcCursorHidden) {
        SoftCursorSaveArea();
        SoftCursorDraw();
        rcCursorHidden = false;
    }
    rcLockSet = false;
}

// SoftCursorMove(). Moves soft cursor in particular location. This
// function respects locking of screen areas so when the cursor is
// moved in the locked area, it becomes invisible until
// SoftCursorUnlockScreen() method is called.
void ClientConnection::SoftCursorMove(int x, int y)
{
    omni_mutex_lock l(m_cursorMutex);

    if (prevCursorSet && !rcCursorHidden) {
        SoftCursorRestoreArea();
        rcCursorHidden = true;
    }

    rcCursorX = x;
    rcCursorY = y;

    if (prevCursorSet && !(rcLockSet && SoftCursorInLockedArea())) {
        SoftCursorSaveArea();
        SoftCursorDraw();
        rcCursorHidden = false;
    }
}

// Free all data associated with cursor.
void ClientConnection::SoftCursorFree()
{
    omni_mutex_lock l(m_cursorMutex);

    if (prevCursorSet) {
        if (!rcCursorHidden)
            SoftCursorRestoreArea();
        DeleteObject(m_hSavedAreaBitmap);
        DeleteDC(m_hSavedAreaDC);
        delete[] rcSource;
        rcSource=NULL;
        delete[] rcMask;
        rcMask=NULL;
        prevCursorSet = false;
    }
}

//////////////////////////////////////////////////////////////////
//
// Low-level methods implementing software cursor functionality.
//
// Check if cursor is within locked part of screen.
bool ClientConnection::SoftCursorInLockedArea()
{
    return (rcLockX < rcCursorX - rcHotX + rcWidth &&
            rcLockY < rcCursorY - rcHotY + rcHeight &&
            rcLockX + rcLockWidth > rcCursorX - rcHotX &&
            rcLockY + rcLockHeight > rcCursorY - rcHotY);
}

// Save screen data in memory buffer.
void ClientConnection::SoftCursorSaveArea()
{
    RECT r;
    SoftCursorToScreen(&r, NULL);
    int x = r.left;
    int y = r.top;
    int w = r.right - r.left;
    int h = r.bottom - r.top;

    omni_mutex_lock l(m_bitmapdcMutex);
    ObjectSelector b1(m_hBitmapDC, m_hBitmap);
    PaletteSelector ps1(m_hBitmapDC, m_hPalette);
    ObjectSelector b2(m_hSavedAreaDC, m_hSavedAreaBitmap);
    PaletteSelector ps2(m_hSavedAreaDC, m_hPalette);

    if (!BitBlt(m_hSavedAreaDC, 0, 0, w, h, m_hBitmapDC, x, y, SRCCOPY)) {
        vnclog.Print(0, _T("Error saving screen under cursor\n"));
    }
}

// Restore screen data saved in memory buffer.
void ClientConnection::SoftCursorRestoreArea()
{
    RECT r;
    SoftCursorToScreen(&r, NULL);
    int x = r.left;
    int y = r.top;
    int w = r.right - r.left;
    int h = r.bottom - r.top;

    omni_mutex_lock l(m_bitmapdcMutex);
    ObjectSelector b1(m_hBitmapDC, m_hBitmap);
    PaletteSelector ps1(m_hBitmapDC, m_hPalette);
    ObjectSelector b2(m_hSavedAreaDC, m_hSavedAreaBitmap);
    PaletteSelector ps2(m_hSavedAreaDC, m_hPalette);

    if (!BitBlt(m_hBitmapDC, x, y, w, h, m_hSavedAreaDC, 0, 0, SRCCOPY)) {
        vnclog.Print(0, _T("Error restoring screen under cursor\n"));
    }

    InvalidateScreenRect(&r);
}

// Draw cursor.
void ClientConnection::SoftCursorDraw()
{
    int x, y, x0, y0;
    int offset;

    omni_mutex_lock l(m_bitmapdcMutex);
    ObjectSelector b(m_hBitmapDC, m_hBitmap);
    PaletteSelector p(m_hBitmapDC, m_hPalette);

    SETUP_COLOR_SHORTCUTS;

    for (y = 0; y < rcHeight; y++) {
        y0 = rcCursorY - rcHotY + y;
        if (y0 >= 0 && y0 < m_si.framebufferHeight) {
            for (x = 0; x < rcWidth; x++) {
                x0 = rcCursorX - rcHotX + x;
                if (x0 >= 0 && x0 < m_si.framebufferWidth) {
                    offset = y * rcWidth + x;
                    if (rcMask[offset]) {
                        SETPIXEL(m_hBitmapDC, x0, y0, rcSource[offset]);
                    }
                }
            }
        }
    }
    RECT r;
    SoftCursorToScreen(&r, NULL);
    InvalidateScreenRect(&r);
}

// Calculate position, size and offset for the part of cursor
// located inside framebuffer bounds.
void ClientConnection::SoftCursorToScreen(RECT *screenArea, POINT *cursorOffset)
{
    int cx = 0, cy = 0;

    int x = rcCursorX - rcHotX;
    int y = rcCursorY - rcHotY;
    int w = rcWidth;
    int h = rcHeight;

    if (x < 0) {
        cx = -x;
        w -= cx;
        x = 0;
    } else if (x + w > m_si.framebufferWidth) {
        w = m_si.framebufferWidth - x;
    }
    if (y < 0) {
        cy = -y;
        h -= cy;
        y = 0;
    } else if (y + h > m_si.framebufferHeight) {
        h = m_si.framebufferHeight - y;
    }

    if (w < 0) {
        cx = 0; x = 0; w = 0;
    }
    if (h < 0) {
        cy = 0; y = 0; h = 0;
    }

    if (screenArea != NULL) {
        SetRect(screenArea, x, y, x + w, y + h);
    }
    if (cursorOffset != NULL) {
        cursorOffset->x = cx;
        cursorOffset->y = cy;
    }
}

void ClientConnection::InvalidateScreenRect(const RECT *pRect) {
    RECT rect;

    // If we're scaling, we transform the coordinates of the rectangle
    // received into the corresponding window coords, and invalidate
    // *that* region.
    if (m_opts.m_scaling) {
        // First, we adjust coords to avoid rounding down when scaling.
        int n = m_opts.m_scale_num;
        int d = m_opts.m_scale_den;
        int left   = (pRect->left / d) * d;
        int top    = (pRect->top  / d) * d;
        int right  = (pRect->right  + d - 1) / d * d; // round up
        int bottom = (pRect->bottom + d - 1) / d * d; // round up

        // Then we scale the rectangle, which should now give whole numbers.
        rect.left   = (left   * n / d) - m_hScrollPos;
        rect.top    = (top    * n / d) - m_vScrollPos;
        rect.right  = (right  * n / d) - m_hScrollPos;
        rect.bottom = (bottom * n / d) - m_vScrollPos;
    } else {
        rect.left   = pRect->left   - m_hScrollPos;
        rect.top    = pRect->top    - m_vScrollPos;
        rect.right  = pRect->right  - m_hScrollPos;
        rect.bottom = pRect->bottom - m_vScrollPos;
    }
    InvalidateRect(m_hwnd, &rect, FALSE);
}

void ClientConnection::InvalidateRegion(const RECT *pRect,HRGN *prgn) {
    RECT rect;

    // If we're scaling, we transform the coordinates of the rectangle
    // received into the corresponding window coords, and invalidate
    // *that* region.
    if (m_opts.m_scaling) {
        // First, we adjust coords to avoid rounding down when scaling.
        int n = m_opts.m_scale_num;
        int d = m_opts.m_scale_den;
        int left   = (pRect->left / d) * d;
        int top    = (pRect->top  / d) * d;
        int right  = (pRect->right  + d - 1) / d * d; // round up
        int bottom = (pRect->bottom + d - 1) / d * d; // round up

        // Then we scale the rectangle, which should now give whole numbers.
        rect.left   = (left   * n / d) - m_hScrollPos;
        rect.top    = (top    * n / d) - m_vScrollPos;
        rect.right  = (right  * n / d) - m_hScrollPos;
        rect.bottom = (bottom * n / d) - m_vScrollPos;
    } else {
        rect.left   = pRect->left   - m_hScrollPos;
        rect.top    = pRect->top    - m_vScrollPos;
        rect.right  = pRect->right  - m_hScrollPos;
        rect.bottom = pRect->bottom - m_vScrollPos;
    }
    HRGN tempregion = CreateRectRgnIndirect(&rect);
    CombineRgn(*prgn,*prgn,tempregion,RGN_OR);
    DeleteObject(tempregion);
}
  评论这张
 
阅读(1249)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017