VNC源码阅读--VNC图像更新机制(1)
VNC的图像更新机制核心为,桌面区域更新记录策略和更新区域通知策略。桌面更新区域记录主要是通过
hooks记录桌面上变化的矩形区域,只记录更新的矩形区不记录具体更新的数据。更新区域记录步骤大致如下:1.wm_hooks截获桌面变化的相关消息,并转化为自定义的消息发送给WMHooksThread线程处理。 2. WMHooksThread 中用SimpleUpdateTracker new_changes记录新的更新区域.3.把SimpleUpdateTracker new_changes更新拷贝到SDisplay中。4.每次要发送桌面更新的时候,把SDisplay中记录的更新区域传给VNCServerST 对象中。更新区域的通知主要有poll和push两种机制。push是服务器每隔10ms检查有没有更新,如果有更新则主动把更新推送给客户端,poll机制则是客户端主动请求更新,客户端通过发送framebufferupdate请求某一个区域更新,服务器处理该消息发送相应的更新。详细分析如下:
1.Wm_hooks截获消息并转化为自定义的消息发送给
WMHooksThread线程处理。
Wm_hooks自定义的消息:
UINT WM_HK_WindowChanged = RegisterWindowMessage(_T(
"RFB.WM_Hooks.WindowChanged"));
UINT WM_HK_WindowClientAreaChanged = UINT WM_HK_WindowBorderChanged = RegisterWindowMessage(_T(
"RFB.WM_Hooks.WindowBorderChanged"));
UINT WM_HK_RectangleChanged = RegisterWindowMessage(_T(
"RFB.WM_Hooks.RectangleChanged"));
UINT WM_HK_CursorChanged = RegisterWindowMessage(_T(
"RFB.WM_Hooks.CursorChanged"));
钩子截获到消息以后,把它转化为自定义的消息,然后发送给
WMHooksThread线程处理,消息转化如下:
边框更新消息:
WM_NCPAINT,WM_NCACTIVATE
客户区域更新消息:
BM_SETCHECK, BM_SETSTATE,EM_SETSEL,WM_CHAR,WM_ENABLE,WM_KEYUP,WM_LBUTTONUP,WM_MBUTTONUP,WM_PALETTECHANGED,WM_RBUTTONUP,WM_SYSCOLORCHANGE,WM_SETTEXT。
窗口改变消息:
WM_HSCROLL,WM_VSCROLL,482,485。
矩形区更新消息:
WM_DESTROY
窗口客户区消息:
WM_PAINT
鼠标消息:
WM_NCMOUSEMOVE,WM_MOUSEMOVE
2 . WMHooksThread 中用
SimpleUpdateTracker new_changes记录新的更新区域
WMHooksThread::run() 函数中先判断出矩形区域改变的大小,然后调用
NotifyHooksRegion(const Region& r)把改变的区域记录到SimpleUpdateTracker new_changes中。
NotifyHooksRegion(
const Region& r) {
Lock l(hook_mgr_lock);
std::list<WMHooks*>::iterator i;
for (i=hooks.begin(); i!=hooks.end(); i++) {
(*i)->new_changes.add_changed(r);
if (!(*i)->notified) {
(*i)->notified = true;
PostMessage((*i)->getHandle(), WM_USER, 0, 0); // 把消息通知到
clipper见下面一个处理函数
}
}
}
3.把更新区域拷贝到
SDisplay中
rfb::win32::WMHooks::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_USER:
{
Sleep(0);
Lock l(hook_mgr_lock);
notified = false;
new_changes.get_update(*clipper); //把更新通知到
clipper中
new_changes.clear();
}
break;
}
return MsgWindow::processMessage(msg, wParam, lParam);
}
Cliper在下面设置
rfb::win32::WMHooks::setUpdateTracker(UpdateTracker* ut) {
if (clipper)
delete clipper;
clipper =
new ClippedUpdateTracker(*ut);
clipper->set_clip_region(clip_region);
return AddHook(
this);
}
UpdateTracker* ut为
void SDisplay::start(VNCServer*vs)中设置
core->using_hooks = core->wm_hooks.setUpdateTracker(this);
4.把
SDisplay中记录的数据传给VNCServerST 对象
在
SDisplay::processEvent(HANDLE event) {
try_update = flushChangeTracker() || try_update; //把变化的区域拷贝到
VNCServerST中
if (try_update)
server->tryUpdate(); //把更新发送给服务器
}
flushChangeTracker()实现如下:
bool SDisplay::flushChangeTracker() {
if (change_tracker.is_empty())
return false;
change_tracker.translate(screenRect.tl.negate());
change_tracker.get_update(*server); //server 实际指向
VNCServerST 对象该函数把SDisplay中的更新拷贝到VNCServerST中。
change_tracker.clear();
return
true;
}
|
转载于:https://blog.51cto.com/laokaddk/664198