📄 vncdesktop.cpp
字号:
for (int x=0; x<cliplen; x++)
{
if (cliptext[x] != '\x0d')
{
unixtext[unixpos] = cliptext[x];
unixpos++;
}
}
unixtext[unixpos] = 0;
// Free the clip text
free(cliptext);
cliptext = NULL;
// Now send the unix text to the server
_this->m_server->UpdateClipText(unixtext);
free(unixtext);
}
}
_this->m_initialClipBoardSeen = TRUE;
if (_this->m_hnextviewer != NULL)
{
// Pass the message to the next window in clipboard viewer chain.
return SendMessage(_this->m_hnextviewer, WM_DRAWCLIPBOARD, 0,0);
}
return 0;
default:
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
}
BOOL vncDesktop::CheckUpdates()
{
#ifndef _DEBUG
try
{
#endif
// Re-install polling timer if necessary
if (m_server->PollingCycleChanged())
{
SetPollingTimer();
m_server->PollingCycleChanged(false);
}
// Update the state of blank screen timer
UpdateBlankScreenTimer();
// Has the display resolution or desktop changed?
if (m_displaychanged || !vncService::InputDesktopSelected() || !inConsoleSession())
{
vnclog.Print(LL_STATE, VNCLOG("display resolution or desktop changed.\n"));
rfbServerInitMsg oldscrinfo = m_scrinfo;
m_displaychanged = FALSE;
// Attempt to close the old hooks
if (!Shutdown())
{
vnclog.Print(LL_INTERR, VNCLOG("failed to close desktop server.\n"));
m_server->KillAuthClients();
return FALSE;
}
// Now attempt to re-install them!
ChangeResNow();
if (!Startup())
{
vnclog.Print(LL_INTERR, VNCLOG("failed to re-start desktop server.\n"));
m_server->KillAuthClients();
return FALSE;
}
// Check if the screen info has changed
vnclog.Print(LL_INTINFO,
VNCLOG("SCR: old screen format %dx%dx%d\n"),
oldscrinfo.framebufferWidth,
oldscrinfo.framebufferHeight,
oldscrinfo.format.bitsPerPixel);
vnclog.Print(LL_INTINFO,
VNCLOG("SCR: new screen format %dx%dx%d\n"),
m_scrinfo.framebufferWidth,
m_scrinfo.framebufferHeight,
m_scrinfo.format.bitsPerPixel);
if (memcmp(&m_scrinfo, &oldscrinfo, sizeof(oldscrinfo)) != 0)
{
vnclog.Print(LL_INTINFO, VNCLOG("screen format has changed.\n"));
}
// Call this regardless of screen format change
m_server->UpdateLocalFormat();
// Add a full screen update to all the clients
m_changed_rgn.AddRect(m_bmrect);
m_server->UpdatePalette();
}
// TRIGGER THE UPDATE
RECT rect = m_server->GetSharedRect();
RECT new_rect = GetSourceRect();
IntersectRect(&new_rect, &new_rect, &m_bmrect);
// Update screen size if required
if (!EqualRect(&new_rect, &rect))
{
m_server->SetSharedRect(new_rect);
bool sendnewfb = false;
if (rect.right - rect.left != new_rect.right - new_rect.left ||
rect.bottom - rect.top != new_rect.bottom - new_rect.top)
sendnewfb = true;
// FIXME: We should not send NewFBSize if a client
// did not send framebuffer update request.
m_server->SetNewFBSize(sendnewfb);
m_changed_rgn.Clear();
if (sendnewfb && m_server->WindowShared())
{
if (new_rect.right - new_rect.left == 0 &&
new_rect.bottom - new_rect.top == 0)
{
// window is minimized
return TRUE;
}
else
{
// window is restored
// window is resized
m_changed_rgn.AddRect(new_rect);
}
}
else
{
return TRUE;
}
}
// If we have clients full region requests
if (m_server->FullRgnRequested())
{
// Capture screen to main buffer
CaptureScreen(rect, m_mainbuff);
// If we have a video driver - reset counter
if ( m_videodriver != NULL && m_videodriver->IsActive())
{
m_videodriver->ResetCounter();
}
}
// DEBUG: Continue auditing the code from this point.
// If we have incremental update requests
if (1 || m_server->IncrRgnRequested())
{
vncRegion rgn;
// Use either a mirror video driver, or perform polling
if (m_videodriver != NULL && m_videodriver->IsActive())
{
// FIXME: If there were no incremental update requests
// for some time, we will loose updates.
// IMPORTANT: Mirage outputs the regions re (0, 0)
// so we have to offset them re virtual display
// TODOTODO
BOOL bCursorShape = FALSE;
m_videodriver->HandleDriverChanges(
this,
m_changed_rgn,
m_bmrect.left,
m_bmrect.top,
bCursorShape);
}
else
{
if (GetPollingFlag())
{
SetPollingFlag(false);
PerformPolling();
}
}
// Check for moved windows
// PrimaryDisplayOnlyShared: check if any problems when
// dragging from another display
if ((m_server->FullScreen() || m_server->PrimaryDisplayOnlyShared()) &&
!(m_videodriver && m_videodriver->IsHandlingScreen2ScreenBlt()))
{
CalcCopyRects();
}
if (m_copyrect_set)
{
// Send copyrect to all clients
m_server->CopyRect(m_copyrect_rect, m_copyrect_src);
m_copyrect_set = false;
// IMPORTANT: this order: CopyRectToBuffer, CaptureScreen, GetChangedRegion
// Copy old window rect to back buffer
CopyRectToBuffer(m_copyrect_rect, m_copyrect_src);
// Copy new window rect to main buffer
CaptureScreen(m_copyrect_rect, m_mainbuff);
// Get changed pixels to rg
GetChangedRegion(rgn, m_copyrect_rect);
RECT rect;
rect.left= m_copyrect_src.x;
rect.top = m_copyrect_src.y;
rect.right = rect.left + (m_copyrect_rect.right - m_copyrect_rect.left);
rect.bottom = rect.top + (m_copyrect_rect.bottom - m_copyrect_rect.top);
// Refresh old window rect
m_changed_rgn.AddRect(rect);
// Don't refresh new window rect
m_changed_rgn.SubtractRect(m_copyrect_rect);
}
// Get only desktop area
vncRegion temprgn;
temprgn.Clear();
temprgn.AddRect(rect);
m_changed_rgn.Intersect(temprgn);
// Get list of rectangles for checking
rectlist rectsToScan;
m_changed_rgn.Rectangles(rectsToScan);
// Capture and check them
CheckRects(rgn, rectsToScan);
// Update the mouse
m_server->UpdateMouse();
// Send changed region data to all clients
m_server->UpdateRegion(rgn);
// Save changes to region
m_last_changed_rgn.Clear();
m_last_changed_rgn.Combine(m_changed_rgn);
// Clear changed region
m_changed_rgn.Clear();
}
// Trigger an update to be sent
if (m_server->FullRgnRequested() || m_server->IncrRgnRequested())
{
m_server->TriggerUpdate();
}
#ifndef _DEBUG
}
catch (...)
{
vnclog.Print(LL_INTERR, VNCLOG("vncDesktop::CheckUpdates caught an exception.\n"));
m_server->KillAuthClients();
return FALSE;
}
#endif
return TRUE;
}
void
vncDesktop::SetPollingTimer()
{
const UINT driverCycle = 30;
const UINT minPollingCycle = 5;
UINT msec;
if (m_videodriver != NULL) {
msec = driverCycle;
} else {
msec = m_server->GetPollingCycle() / 16;
if (msec < minPollingCycle) {
msec = minPollingCycle;
}
}
m_timer_polling = SetTimer(Window(), TIMER_POLL, msec, NULL);
}
inline void vncDesktop::CheckRects(vncRegion &rgn, rectlist &rects)
{
#ifndef _DEBUG
try
{
#endif
rectlist::iterator i;
for (i = rects.begin(); i != rects.end(); i++)
{
// Copy data to the main buffer
// FIXME: Maybe call CaptureScreen() just once?
// Check what would be more efficient.
CaptureScreen(*i, m_mainbuff);
// Check for changes in the rectangle
GetChangedRegion(rgn, *i);
}
#ifndef _DEBUG
}
catch (...)
{
vnclog.Print(LL_INTERR, VNCLOG("vncDesktop::CheckRects caught an exception.\n"));
throw;
}
#endif
}
// This notably improves performance when using Visual C++ 6.0 compiler
#pragma function(memcpy, memcmp)
static const int BLOCK_SIZE = 32;
// created for troubleshoot purposes;
// when GetChangedRegion_Normal et al are suspected for bugs/need changes.
// the code below is as simple and clear as possible
void vncDesktop::GetChangedRegion_Dummy(vncRegion &rgn, const RECT &rect)
{
rgn.AddRect(rect);
// Copy the changes to the back buffer
const int c2rect_re_vd_top = rect.top - m_bmrect.top;
const int c3rect_re_vd_left = rect.left - m_bmrect.left;
_ASSERTE(c2rect_re_vd_top >= 0);
_ASSERTE(c3rect_re_vd_left >= 0);
const UINT bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
const int offset = c2rect_re_vd_top * m_bytesPerRow + c3rect_re_vd_left * bytesPerPixel;
unsigned char *o_ptr = m_backbuff + offset;
unsigned char *n_ptr = m_mainbuff + offset;
const int bytes_in_row = (rect.right - rect.left) * bytesPerPixel;
for (int y = rect.top; y < rect.bottom; y++)
{
memcpy(o_ptr, n_ptr, bytes_in_row);
n_ptr += m_bytesPerRow;
o_ptr += m_bytesPerRow;
}
}
void vncDesktop::GetChangedRegion_Normal(vncRegion &rgn, const RECT &rect)
{
const UINT bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
const int bytes_per_scanline = (rect.right - rect.left) * bytesPerPixel;
const int crect_re_vd_left = rect.left - m_bmrect.left;
const int crect_re_vd_top = rect.top - m_bmrect.top;
_ASSERTE(crect_re_vd_left >= 0);
_ASSERTE(crect_re_vd_top >= 0);
const int offset = crect_re_vd_top * m_bytesPerRow + crect_re_vd_left * bytesPerPixel;
unsigned char *o_ptr = m_backbuff + offset;
unsigned char *n_ptr = m_mainbuff + offset;
RECT new_rect = rect;
// Fast processing for small rectangles
if (rect.right - rect.left <= BLOCK_SIZE &&
rect.bottom - rect.top <= BLOCK_SIZE)
{
for (int y = rect.top; y < rect.bottom; y++)
{
if (memcmp(o_ptr, n_ptr, bytes_per_scanline) != 0)
{
new_rect.top = y;
UpdateChangedSubRect(rgn, new_rect);
break;
}
o_ptr += m_bytesPerRow;
n_ptr += m_bytesPerRow;
}
return;
}
// Process bigger rectangles
BOOL bTop4Move = TRUE;
for (int y = rect.top; y < rect.bottom; y++)
{
if (memcmp(o_ptr, n_ptr, bytes_per_scanline) != 0)
{
if (bTop4Move)
{
new_rect.top = y;
bTop4Move = FALSE;
}
// Skip a number of lines after a non-matched one
int n = BLOCK_SIZE / 2 - 1;
y += n;
o_ptr += n * m_bytesPerRow;
n_ptr += n * m_bytesPerRow;
}
else
{
if (!bTop4Move)
{
new_rect.bottom = y;
UpdateChangedRect(rgn, new_rect);
bTop4Move = TRUE;
}
}
o_ptr += m_bytesPerRow;
n_ptr += m_bytesPerRow;
}
if (!bTop4Move)
{
new_rect.bottom = rect.bottom;
UpdateChangedRect(rgn, new_rect);
}
}
void vncDesktop::UpdateChangedRect(vncRegion &rgn, const RECT &rect)
{
// Pass small rectangles directly to UpdateChangedSubRect
if (rect.right - rect.left <= BLOCK_SIZE &&
rect.bottom - rect.top <= BLOCK_SIZE)
{
UpdateChangedSubRect(rgn, rect);
return;
}
const UINT bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
RECT new_rect;
int x, y, ay;
const int crect_re_vd_left = rect.left - m_bmrect.left;
const int crect_re_vd_top = rect.top - m_bmrect.top;
_ASSERTE(crect_re_vd_left >= 0);
_ASSERTE(crect_re_vd_top >= 0);
// Scan down the rectangle
const int offset = crect_re_vd_top * m_bytesPerRow + crect_re_vd_left * bytesPerPixel;
unsigned char *o_topleft_ptr = m_backbuff + offset;
unsigned char *n_topleft_ptr = m_mainbuff + offset;
for (y = rect.top; y < rect.bottom; y += BLOCK_SIZE)
{
// Work out way down the bitmap
unsigned char *o_row_ptr = o_topleft_ptr;
unsigned char *n_row_ptr = n_topleft_ptr;
const int blockbottom = Min(y + BLOCK_SIZE, rect.bottom);
new_rect.bottom = blockbottom;
BOOL bLeft4Move = TRUE;
for (x = rect.left; x < rect.right; x += BLOCK_SIZE)
{
// Work our way across the row
unsigned char *n_block_ptr = n_row_ptr;
unsigned char *o_block_ptr = o_row_ptr;
const UINT blockright = Min(x + BLOCK_SIZE, rect.right);
const UINT bytesPerBlockRow = (blockright-x) * bytesPerPixel;
// Scan this block
for (ay = y; ay < blockbottom; ay++)
{
if (memcmp(n_block_ptr, o_block_ptr, bytesPerBlockRow) != 0)
break;
n_block_ptr += m_bytesPerRow;
o_block_ptr += m_bytesPerRow;
}
if (ay < blockbottom)
{
// There were changes, so this block will need to be updated
if (bLeft4Move)
{
new_rect.left = x;
bLeft4Move = FALSE;
new_rect.top = ay;
}
else if (ay < new_rect.top)
{
new_rect.top = ay;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -