#include "vncdesktopthread.h" int counterwatch;//global var for driverwatch bool g_DesktopThread_running; bool g_update_triggered; inline bool ClipRect(int *x, int *y, int *w, int *h, int cx, int cy, int cw, int ch) { if (*x < cx) { *w -= (cx-*x); *x = cx; } if (*y < cy) { *h -= (cy-*y); *y = cy; } if (*x+*w > cx+cw) { *w = (cx+cw)-*x; } if (*y+*h > cy+ch) { *h = (cy+ch)-*y; } return (*w>0) && (*h>0); } #ifdef DRIVER //////////////////////////////////////////////////////////////////////////////////// // Modif rdv@2002 - v1.1.x - videodriver void vncDesktopThread::copy_bitmaps_to_buffer(ULONG i,rfb::Region2D &rgncache,rfb::UpdateTracker &tracker) { rfb::Rect rect; int x = m_desktop->pchanges_buf->pointrect[i].rect.left; int w = m_desktop->pchanges_buf->pointrect[i].rect.right-m_desktop->pchanges_buf->pointrect[i].rect.left; int y = m_desktop->pchanges_buf->pointrect[i].rect.top; int h = m_desktop->pchanges_buf->pointrect[i].rect.bottom-m_desktop->pchanges_buf->pointrect[i].rect.top; //vnclog.Print(LL_INTINFO, VNCLOG("Driver ************* %i %i %i %i \n"),x,y,w,h); if (!ClipRect(&x, &y, &w, &h, m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.tl.y, m_desktop->m_bmrect.br.x-m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.br.y-m_desktop->m_bmrect.tl.y)) return; //vnclog.Print(LL_INTINFO, VNCLOG("Driver ************* %i %i %i %i \n"),x,y,w,h); rect.tl.x = x; rect.br.x = x+w; rect.tl.y = y; rect.br.y = y+h; switch(m_desktop->pchanges_buf->pointrect[i].type) { case SCREEN_SCREEN: { int dx=m_desktop->pchanges_buf->pointrect[i].point.x; int dy=m_desktop->pchanges_buf->pointrect[i].point.y; if (!m_screen_moved && (dx==0 || dy==0) ) { x=x-dx;; y=y-dy;; if (!ClipRect(&x,&y,&w,&h,m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.tl.y, m_desktop->m_bmrect.br.x-m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.br.y-m_desktop->m_bmrect.tl.y)) return; rect.tl.x=x+dx; rect.tl.y=y+dy; rect.br.x=x+w+dx; rect.br.y=y+h+dy; rfb::Point delta = rfb::Point(-dx,-dy); rgncache=rgncache.union_(rect); tracker.add_copied(rect, delta); // vnclog.Print(LL_INTINFO, VNCLOG("Copyrect \n")); } else { rgncache=rgncache.union_(rect); } break; } case SOLIDFILL: case TEXTOUT: case BLEND: case TRANS: case PLG: case BLIT:; rgncache=rgncache.union_(rect); break; default: break; } } // Modif rdv@2002 - v1.1.x - videodriver BOOL vncDesktopThread::handle_driver_changes(rfb::Region2D &rgncache,rfb::UpdateTracker &tracker) { omni_mutex_lock l(m_desktop->m_videodriver_lock); int oldaantal=m_desktop->m_videodriver->oldaantal; int counter=m_desktop->pchanges_buf->counter; int nr_updates=m_desktop->pchanges_buf->pointrect[0].type; vnclog.Print(LL_INTERR, VNCLOG("updates, rects %i %i\n"),m_desktop->pchanges_buf->pointrect[0].type,oldaantal-counter); m_desktop->pchanges_buf->pointrect[0].type=0; if (oldaantal==counter) return FALSE; if (counter<1 || counter >1999) return FALSE; if (!m_server->SingleWindow()) m_screen_moved=m_desktop->CalcCopyRects(tracker); else m_screen_moved=true; /// HEITE01E // buffer was overloaded, so we use the bounding rect if (nr_updates>2000) { rfb::Rect rect; int x = m_desktop->pchanges_buf->pointrect[0].rect.left; int w = m_desktop->pchanges_buf->pointrect[0].rect.right-m_desktop->pchanges_buf->pointrect[0].rect.left; int y = m_desktop->pchanges_buf->pointrect[0].rect.top; int h = m_desktop->pchanges_buf->pointrect[0].rect.bottom-m_desktop->pchanges_buf->pointrect[0].rect.top; if (ClipRect(&x, &y, &w, &h, m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.tl.y, m_desktop->m_bmrect.br.x-m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.br.y-m_desktop->m_bmrect.tl.y)) { rect.tl.x = x; rect.br.x = x+w; rect.tl.y = y; rect.br.y = y+h; rgncache=rgncache.union_(rect); m_desktop->m_videodriver->oldaantal=counter; } return TRUE; } if (m_server->SingleWindow()) m_screen_moved=true; if (oldaantalm_videodriver->oldaantal=counter; // A lot updates left after combining // This generates an overflow // We expand each single update to minimum 32x32 if (rgncache.Numrects()>150) { rfb::Region2D rgntemp; rfb::RectVector rects; rfb::RectVector::iterator i; rgncache.get_rects(rects, 1, 1); for (i = rects.begin(); i != rects.end(); i++) { rfb::Rect rect = *i; rect.tl.x=rect.tl.x/32*32; rect.tl.y=rect.tl.y/32*32; rect.br.x=rect.br.x/32*32+32; rect.br.y=rect.br.y/32*32+32; if (rect.br.x>m_desktop->m_bmrect.br.x) rect.br.x=m_desktop->m_bmrect.br.x; if (rect.br.y>m_desktop->m_bmrect.br.y) rect.br.y=m_desktop->m_bmrect.br.y; rgntemp=rgntemp.union_(rect); } //Still to many little updates //Use the bounding rectangle for updates if (rgntemp.Numrects()>50) { Rect brect=rgntemp.get_bounding_rect(); rgncache.clear(); rgncache=rgncache.union_(brect); } else { rgncache.clear(); rgncache=rgncache.union_(rgntemp); } } return TRUE; } #endif BOOL vncDesktopThread::Init(vncDesktop *desktop, vncServer *server) { // Save the server pointer m_server = server; m_desktop = desktop; m_returnset = FALSE; m_returnsig = new omni_condition(&m_returnLock); // Start the thread start_undetached(); // Wait for the thread to let us know if it failed to init { omni_mutex_lock l(m_returnLock); while (!m_returnset) { m_returnsig->wait(); } } if (m_return==0) g_DesktopThread_running=false; return m_return; } void vncDesktopThread::ReturnVal(BOOL result) { omni_mutex_lock l(m_returnLock); m_returnset = TRUE; m_return = result; m_returnsig->signal(); } void vncDesktopThread::PollWindow(rfb::Region2D &rgn, HWND hwnd) { // Are we set to low-load polling? if (m_server->PollOnEventOnly()) { // Yes, so only poll if the remote user has done something if (!m_server->RemoteEventReceived()) { return; } } // Does the client want us to poll only console windows? if (m_desktop->m_server->PollConsoleOnly()) { char classname[20]; // Yes, so check that this is a console window... if (GetClassName(hwnd, classname, sizeof(classname))) { if ((strcmp(classname, "tty") != 0) && (strcmp(classname, "ConsoleWindowClass") != 0)) { return; } } } RECT rect; // Get the rectangle if (GetWindowRect(hwnd, &rect)) { //Buffer coordinates rect.left-=m_desktop->m_ScreenOffsetx; rect.right-=m_desktop->m_ScreenOffsetx; rect.top-=m_desktop->m_ScreenOffsety; rect.bottom-=m_desktop->m_ScreenOffsety; rfb::Rect wrect = rfb::Rect(rect).intersect(m_desktop->m_Cliprect); if (!wrect.is_empty()) { rgn = rgn.union_(wrect); } } } void * vncDesktopThread::run_undetached(void *arg) { //******************************************************* // INIT //******************************************************* vnclog.Print(LL_INTERR, VNCLOG("Hook changed 1\n")); // Save the thread's "home" desktop, under NT (no effect under 9x) HDESK home_desktop = GetThreadDesktop(GetCurrentThreadId()); vnclog.Print(LL_INTERR, VNCLOG("Hook changed 2\n")); // Attempt to initialise and return success or failure m_desktop->KillScreenSaver(); { keybd_event(VK_CONTROL, 0, 0, 0); keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); Sleep(500); //Give screen some time to kill screensaver } if (!m_desktop->Startup()) { vncService::SelectHDESK(home_desktop); ReturnVal(FALSE); return NULL; } // Succeeded to initialise ok ReturnVal(TRUE); // sf@2003 - Done here to take into account if the driver is actually activated m_desktop->InitHookSettings(); // We set a flag inside the desktop handler here, to indicate it's now safe // to handle clipboard messages m_desktop->SetClipboardActive(TRUE); // All changes in the state of the display are stored in a local // UpdateTracker object, and are flushed to the vncServer whenever // client updates are about to be triggered rfb::SimpleUpdateTracker clipped_updates; rfb::ClippedUpdateTracker updates(clipped_updates, m_desktop->m_Cliprect); clipped_updates.enable_copyrect(true); rfb::Region2D rgncache; // Incoming update messages are collated into a single region cache // The region cache areas are checked for changes before an update // is triggered, and the changed areas are passed to the UpdateTracker rgncache = m_desktop->m_Cliprect; m_server->SetScreenOffset(m_desktop->m_ScreenOffsetx,m_desktop->m_ScreenOffsety,m_desktop->nr_monitors); // The previous cursor position is stored, to allow us to erase the // old instance whenever it moves. rfb::Point oldcursorpos; // The driver gives smaller rectangles to check // if Accuracy is 4 you eliminate pointer updates if (m_desktop->VideoBuffer() && m_desktop->m_hookdriver) m_desktop->m_buffer.SetAccuracy(4); BOOL idle_skip = TRUE; ULONG idle_skip_count = 0; //init vars m_desktop->m_SWSizeChanged=FALSE; m_desktop->m_SWtoDesktop=FALSE; m_desktop->m_SWmoved=FALSE; m_desktop->Hookdll_Changed = true; m_desktop->m_displaychanged=false; m_desktop->m_hookswitch=false; m_desktop->m_hookinited = FALSE; // Set driver cursor state XRichCursorEnabled=m_desktop->m_server->IsXRichCursorEnabled(); #ifdef DRIVER if (!XRichCursorEnabled && m_desktop->m_videodriver) m_desktop->m_videodriver->HardwareCursor(); if (XRichCursorEnabled && m_desktop->m_videodriver) m_desktop->m_videodriver->NoHardwareCursor(); #endif if (XRichCursorEnabled) m_server->UpdateCursorShape(); InvalidateRect(NULL,NULL,TRUE); oldtick=timeGetTime(); //******************************************************* // END INIT //******************************************************* // START PROCESSING DESKTOP MESSAGES MSG msg; while (TRUE) { if (!PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) { // MAX 30fps newtick = timeGetTime(); // Better resolution than GetTickCount ;) if ((newtick-oldtick)<33) { Sleep(33-(newtick-oldtick)); continue; } oldtick=newtick; #ifdef DRIVER if (m_desktop->VideoBuffer() && m_desktop->m_hookdriver) handle_driver_changes(rgncache,updates); #endif m_desktop->m_update_triggered = FALSE; g_update_triggered = FALSE; if (m_desktop->m_timerid==NULL) m_desktop->m_timerid = SetTimer(m_desktop->m_hwnd, 1, 100, NULL); //******************************************************* // HOOKDLL START STOP need to be executed from the thread //******************************************************* if (m_desktop->Hookdll_Changed && !m_desktop->m_hookswitch) { vnclog.Print(LL_INTERR, VNCLOG("Hook changed \n")); m_desktop->StartStophookdll(m_desktop->On_Off_hookdll); if (m_desktop->On_Off_hookdll) m_desktop->m_hOldcursor = NULL; // Force mouse cursor grabbing if hookdll On // Todo: in case of hookdriver Off - Hoodll On -> hookdriver On - Hoodll Off // we must send an empty mouse cursor to the clients so they get rid of their local // mouse cursor bitmap m_desktop->Hookdll_Changed=false; } //******************************************************* // SCREEN DISPLAY HAS CHANGED, RESTART DRIVER (IF Used) //******************************************************* if ( m_desktop->m_displaychanged || //WM_DISPLAYCHANGE !vncService::InputDesktopSelected() || //handle logon and screensaver desktops m_desktop->m_SWtoDesktop || //switch from SW to full desktop or visa versa m_desktop->m_hookswitch|| //hook change request m_desktop->asked_display!=m_desktop->m_buffer.GetDisplay() //monitor change request ) { // We need to wait until viewer has send if he support Size changes if (!m_server->All_clients_initialalized()) { Sleep(30); vnclog.Print(LL_INTERR, VNCLOG("Wait for viewer init \n")); } //logging if (m_desktop->m_displaychanged) vnclog.Print(LL_INTERR, VNCLOG("++++Screensize changed \n")); if (m_desktop->m_SWtoDesktop) vnclog.Print(LL_INTERR, VNCLOG("m_SWtoDesktop \n")); if (m_desktop->m_hookswitch) vnclog.Print(LL_INTERR, VNCLOG("m_hookswitch \n")); if (m_desktop->asked_display!=m_desktop->m_buffer.GetDisplay()) vnclog.Print(LL_INTERR, VNCLOG("desktop switch %i %i \n"),m_desktop->asked_display,m_desktop->m_buffer.GetDisplay()); if (!vncService::InputDesktopSelected()) vnclog.Print(LL_INTERR, VNCLOG("++++InputDesktopSelected \n")); //Disable driver for logon and screensaver windows //if (!vncService::InputDesktopSelected()) m_desktop->Temp_Resolution=true; BOOL screensize_changed=false; BOOL monitor_changed=false; rfbServerInitMsg oldscrinfo; //******************************************************* // Lock Buffers from here //******************************************************* { if (XRichCursorEnabled) m_server->UpdateCursorShape(); /// We lock all buffers,,and also back the client thread update mechanism if (XRichCursorEnabled) m_server->UpdateCursorShape(); omni_mutex_lock l(m_desktop->m_update_lock); // We remove all queue updates from the tracker m_server->Clear_Update_Tracker(); // Also clear the current updates rgncache.clear(); // Also clear the copy_rect updates clipped_updates.clear(); // TESTTESTTEST // Are all updates cleared....old updates could generate bounding errors // any other queues to clear ? Yep cursor positions m_desktop->m_cursorpos.tl.x=0; m_desktop->m_cursorpos.tl.y=0; m_desktop->m_cursorpos.br.x=0; m_desktop->m_cursorpos.br.y=0; //keep a copy of the old screen size, so we can check for changes later on oldscrinfo = m_desktop->m_scrinfo; if (m_desktop->asked_display!=m_desktop->m_buffer.GetDisplay()) { m_desktop->Checkmonitors(); m_desktop->asked_display=m_desktop->m_buffer.GetDisplay(); int old_monitor=m_desktop->current_monitor; m_desktop->current_monitor=1; if (m_desktop->asked_display==2 && m_desktop->nr_monitors>1) m_desktop->current_monitor=2; if (m_desktop->asked_display==3 && m_desktop->nr_monitors>1) m_desktop->current_monitor=3; vnclog.Print(LL_INTERR, VNCLOG("OLd Current mon %i %i \n"),old_monitor,m_desktop->current_monitor); if ( old_monitor!=m_desktop->current_monitor) monitor_changed=true; } //******************************************************* // Reinitialize buffers,color, etc // monitor change, for non driver, use another buffer //******************************************************* if (m_desktop->m_displaychanged || !vncService::InputDesktopSelected() || m_desktop->m_hookswitch || (monitor_changed #ifdef DRIVER && !m_desktop->m_videodriver #endif )) { // Attempt to close the old hooks // shutdown(true) driver is reinstalled without shutdown,(shutdown need a 640x480x8 switch) vnclog.Print(LL_INTERR, VNCLOG("m_desktop->Shutdown")); monitor_changed=false; if (!m_desktop->Shutdown()) { vnclog.Print(LL_INTERR, VNCLOG("Shutdown KillAuthClients\n")); m_server->KillAuthClients(); break; } bool fHookDriverWanted = m_desktop->m_hookdriver; vnclog.Print(LL_INTERR, VNCLOG("m_desktop->Startup")); if (!m_desktop->Startup()) { vnclog.Print(LL_INTERR, VNCLOG("Startup KillAuthClients\n")); m_server->KillAuthClients(); break; } #ifdef DRIVER if (m_desktop->m_videodriver) { if (!XRichCursorEnabled) m_desktop->m_videodriver->HardwareCursor(); else m_desktop->m_videodriver->NoHardwareCursor(); } #endif m_server->SetScreenOffset(m_desktop->m_ScreenOffsetx,m_desktop->m_ScreenOffsety,m_desktop->nr_monitors); // sf@2003 - After a new Startup(), we check if the required video driver // is actually available. If not, we force hookdll // No need for m_hookswitch again because the driver is NOT available anyway. // All the following cases are now handled: // 1. Desktop thread starts with "Video Driver" checked and no video driver available... // -> HookDll forced (handled by the first InitHookSettings() after initial Startup() call // 2. Desktop Thread starts without "Video Driver" checked but available driver // then the user checks "Video Driver" -> Video Driver used // 3. Desktop thread starts with "Video Driver" and available driver used // Then driver is switched off (-> hookDll) // Then the driver is switched on again (-> hook driver used again) // 4. Desktop thread starts without "Video Driver" checked and no driver available // then the users checks "Video Driver" if (fHookDriverWanted #ifdef DRIVER && m_desktop->m_videodriver == NULL #endif ) { vnclog.Print(LL_INTERR, VNCLOG("m_videodriver == NULL \n")); m_desktop->SethookMechanism(true, false); // InitHookSettings() would work as well; } } //******************************************************* // end reinit //******************************************************* if ((m_desktop->m_scrinfo.framebufferWidth != oldscrinfo.framebufferWidth) || (m_desktop->m_scrinfo.framebufferHeight != oldscrinfo.framebufferHeight || m_desktop->m_SWtoDesktop==TRUE )) { screensize_changed=true; vnclog.Print(LL_INTINFO, VNCLOG("SCR: new screen format %dx%dx%d\n"), m_desktop->m_scrinfo.framebufferWidth, m_desktop->m_scrinfo.framebufferHeight, m_desktop->m_scrinfo.format.bitsPerPixel); } m_desktop->m_displaychanged = FALSE; m_desktop->m_hookswitch = FALSE; m_desktop->Hookdll_Changed = m_desktop->On_Off_hookdll; // Set the hooks again if necessary ! m_desktop->m_SWtoDesktop=FALSE; //**************************************************************************** //************* SCREEN SIZE CHANGED //**************************************************************************** if (screensize_changed) { vnclog.Print(LL_INTERR, VNCLOG("Size changed\n")); POINT CursorPos; m_desktop->SWinit(); m_desktop->GetQuarterSize(); GetCursorPos(&CursorPos); CursorPos.x -= m_desktop->m_ScreenOffsetx; CursorPos.y -= m_desktop->m_ScreenOffsety; m_desktop->m_cursorpos.tl = CursorPos; m_desktop->m_cursorpos.br = rfb::Point(GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR)).translate(CursorPos); m_server->SetSWOffset(m_desktop->m_SWOffsetx,m_desktop->m_SWOffsety); // Adjust the UpdateTracker clip region updates.set_clip_region(m_desktop->m_Cliprect); m_desktop->m_buffer.ClearCache(); } if (monitor_changed) { // we are using the driver, so a monitor change is a view change, like a special kind of single window // m_desktop->current_monitor is the new monitor we want to see // monitor size mymonitor[m_desktop->current_monitor-1] // m_SWOffset is used by the encoders to send the correct coordinates to the viewer // Cliprect, buffer coordinates m_desktop->m_SWOffsetx=m_desktop->mymonitor[m_desktop->current_monitor-1].offsetx-m_desktop->mymonitor[2].offsetx; m_desktop->m_SWOffsety=m_desktop->mymonitor[m_desktop->current_monitor-1].offsety-m_desktop->mymonitor[2].offsety; m_server->SetSWOffset(m_desktop->m_SWOffsetx,m_desktop->m_SWOffsety); m_desktop->m_Cliprect.tl.x=m_desktop->mymonitor[m_desktop->current_monitor-1].offsetx-m_desktop->mymonitor[2].offsetx; m_desktop->m_Cliprect.tl.y=m_desktop->mymonitor[m_desktop->current_monitor-1].offsety-m_desktop->mymonitor[2].offsety; m_desktop->m_Cliprect.br.x=m_desktop->mymonitor[m_desktop->current_monitor-1].offsetx+ m_desktop->mymonitor[m_desktop->current_monitor-1].Width-m_desktop->mymonitor[2].offsetx; m_desktop->m_Cliprect.br.y=m_desktop->mymonitor[m_desktop->current_monitor-1].offsety+ m_desktop->mymonitor[m_desktop->current_monitor-1].Height-m_desktop->mymonitor[2].offsety; vnclog.Print(LL_INTERR, VNCLOG("***********###############************ %i %i %i %i %i %i\n"),m_desktop->m_SWOffsetx,m_desktop->m_SWOffsety ,m_desktop->m_Cliprect.tl.x,m_desktop->m_Cliprect.tl.y,m_desktop->m_Cliprect.br.x,m_desktop->m_Cliprect.br.y); rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_Cliprect)); updates.set_clip_region(m_desktop->m_Cliprect); m_desktop->m_buffer.ClearCache(); m_desktop->m_buffer.BlackBack(); } // InvalidateRect(NULL,NULL,TRUE); rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_Cliprect)); } //******************************************************* // End Lock updates // SetNewSWSize also Lock, else we get a deathlock //******************************************************* if (memcmp(&m_desktop->m_scrinfo.format, &oldscrinfo.format, sizeof(rfbPixelFormat)) != 0) { vnclog.Print(LL_INTERR, VNCLOG("Format changed\n")); m_server->UpdatePalette(); m_server->UpdateLocalFormat(); } if (screensize_changed) { screensize_changed=false; m_server->SetNewSWSize(m_desktop->m_scrinfo.framebufferWidth,m_desktop->m_scrinfo.framebufferHeight,FALSE); m_server->SetScreenOffset(m_desktop->m_ScreenOffsetx,m_desktop->m_ScreenOffsety,m_desktop->nr_monitors); } if (monitor_changed) { monitor_changed=false; m_server->SetNewSWSize(m_desktop->mymonitor[m_desktop->current_monitor-1].Width,m_desktop->mymonitor[m_desktop->current_monitor-1].Height,TRUE); } } //******************************************************* // END SCREEN DISPLAY HAS CHANGED //******************************************************* // m_server->SetSWOffset(m_desktop->m_SWOffsetx,m_desktop->m_SWOffsety); //******************************************************************* // SINGLE WINDOW // size SW changed // Position change -->change offsets //******************************************************************* bool SWSizeChanged=false; if (m_server->SingleWindow()) { omni_mutex_lock l(m_desktop->m_update_lock); m_desktop->GetQuarterSize(); m_server->SetSWOffset(m_desktop->m_SWOffsetx,m_desktop->m_SWOffsety); //SW size changed if (m_desktop->m_SWSizeChanged) { SWSizeChanged=true; m_desktop->m_SWSizeChanged=FALSE; m_desktop->GetQuarterSize(); rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_Cliprect)); // vnclog.Print(LL_INTINFO, VNCLOG("4 %i %i %i %i \n"),m_desktop->m_Cliprect.br.x,m_desktop->m_Cliprect.br.y,m_desktop->m_Cliprect.tl.x,m_desktop->m_Cliprect.tl.y); updates.set_clip_region(m_desktop->m_Cliprect); m_server->SetSWOffset(m_desktop->m_SWOffsetx,m_desktop->m_SWOffsety); m_desktop->m_buffer.ClearCache(); m_desktop->m_buffer.BlackBack(); } //SW position changed if (m_desktop->m_SWmoved) { m_desktop->m_SWmoved=FALSE; updates.set_clip_region(m_desktop->m_Cliprect); m_server->SetSWOffset(m_desktop->m_SWOffsetx,m_desktop->m_SWOffsety); rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_Cliprect)); // vnclog.Print(LL_INTINFO, VNCLOG("5 %i %i %i %i \n"),m_desktop->m_Cliprect.br.x,m_desktop->m_Cliprect.br.y,m_desktop->m_Cliprect.tl.x,m_desktop->m_Cliprect.tl.y); m_desktop->m_buffer.ClearCache(); m_desktop->m_buffer.BlackBack(); } } if (m_server->SingleWindow() && SWSizeChanged) { m_server->SetNewSWSize(m_desktop->m_SWWidth,m_desktop->m_SWHeight,FALSE); m_server->SetScreenOffset(m_desktop->m_ScreenOffsetx,m_desktop->m_ScreenOffsety,m_desktop->nr_monitors); } //////////////////////////////////////////////////////////////////////////////// // END DYNAMIC CHANGES //////////////////////////////////////////////////////////////////////////////// // // CALCULATE CHANGES m_desktop->m_UltraEncoder_used=m_desktop->m_server->IsThereAUltraEncodingClient(); if (m_desktop->m_server->UpdateWanted()) { //TEST4 // Re-render the mouse's old location if it's moved BOOL cursormoved = FALSE; POINT cursorpos; if (GetCursorPos(&cursorpos) && ((cursorpos.x != oldcursorpos.x) || (cursorpos.y != oldcursorpos.y))) { cursormoved = TRUE; oldcursorpos = rfb::Point(cursorpos); } //**************************************************************************** //************* Polling ---- no driver //**************************************************************************** if (!m_desktop->m_hookdriver) { // POLL PROBLEM AREAS // We add specific areas of the screen to the region cache, // causing them to be fetched for processing. DWORD lTime = timeGetTime(); if (cursormoved) { m_lLastMouseMoveTime = lTime; } m_desktop->m_buffer.SetAccuracy(m_desktop->m_server->TurboMode() ? 8 : 4); if (m_desktop->m_server->PollFullScreen()) { if ( ( //(lTime - m_lLastUpdateTime > 33) // 30 FPS max // Now Useless with RDV timing above... // && (lTime - m_lLastMouseMoveTime > 100) // 100 ms pause after a Mouse move ) //|| //!m_desktop->m_server->TurboMode() // Only block FS Polling in Turbo Mode... ) { m_lLastUpdateTime = lTime; if ( (lTime - m_lLastMouseMoveTime > 300) // Restart FS Polling 300ms after last mouse move //|| //(!m_desktop->m_server->TurboMode()) // || // (!m_desktop->RestartDriver) ) m_desktop->FastDetectChanges(rgncache, m_desktop->GetSize(), 0, true); } } if (m_desktop->m_server->PollForeground()) { // Get the window rectangle for the currently selected window HWND hwnd = GetForegroundWindow(); if (hwnd != NULL) PollWindow(rgncache, hwnd); } if (m_desktop->m_server->PollUnderCursor()) { // Find the mouse position POINT mousepos; if (GetCursorPos(&mousepos)) { // Find the window under the mouse HWND hwnd = WindowFromPoint(mousepos); if (hwnd != NULL) PollWindow(rgncache, hwnd); } } } //**************************************************************************** //************* driver No polling //**************************************************************************** else { // long lTime = timeGetTime(); if (cursormoved) { // if (lTime - m_desktop->m_lLastMouseUpdateTime < 200) // continue; m_desktop->m_buffer.SetAccuracy(m_desktop->m_server->TurboMode() ? 2 : 1); // m_desktop->m_lLastMouseUpdateTime = lTime; } else // 4 is not that bad...but not perfect (especially with tree branchs display) m_desktop->m_buffer.SetAccuracy(m_desktop->m_server->TurboMode() ? 4 : 2); } // PROCESS THE MOUSE POINTER // Some of the hard work is done in clients, some here // This code fetches the desktop under the old pointer position // but the client is responsible for actually encoding and sending // it when required. // This code also renders the pointer and saves the rendered position // Clients include this when rendering updates. // The code is complicated in this way because we wish to avoid // rendering parts of the screen the mouse moved through between // client updates, since in practice they will probably not have changed. if (cursormoved && !m_desktop->m_hookdriver) { if (!m_desktop->m_cursorpos.is_empty()) { // Cursor position seems to be outsite the bounding // When you make the screen smaller // add extra check rfb::Rect rect; int x = m_desktop->m_cursorpos.tl.x; int w = m_desktop->m_cursorpos.br.x-x; int y = m_desktop->m_cursorpos.tl.y; int h = m_desktop->m_cursorpos.br.y-y; if (ClipRect(&x, &y, &w, &h, m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.tl.y, m_desktop->m_bmrect.br.x-m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.br.y-m_desktop->m_bmrect.tl.y)) { rect.tl.x = x; rect.br.x = x+w; rect.tl.y = y; rect.br.y = y+h; rgncache = rgncache.union_(rect); // vnclog.Print(LL_INTINFO, VNCLOG("6 %i %i %i %i \n"),m_desktop->m_cursorpos.br.x,m_desktop->m_cursorpos.br.y,m_desktop->m_cursorpos.tl.x,m_desktop->m_cursorpos.tl.y); // vnclog.Print(LL_INTINFO, VNCLOG("6 %i %i %i %i \n"),rect.br.x,rect.br.y,rect.tl.x,rect.tl.y); } } } { // Prevent any clients from accessing the Buffer omni_mutex_lock l(m_desktop->m_update_lock); // CHECK FOR COPYRECTS // This actually just checks where the Foreground window is if (!m_desktop->m_hookdriver && !m_server->SingleWindow()) m_desktop->CalcCopyRects(updates); // GRAB THE DISPLAY // Fetch data from the display to our display cache. // Update the scaled rects when using server side scaling // something wrong inithooking again // We make sure no updates are in the regions // sf@2002 - Added "&& m_desktop->m_hookdriver" // Otherwise we're still getting driver updates (from shared memory buffer) // after a m_hookdriver switching from on to off // (and m_hookdll from off to on) that causes mouse cursor garbage, // or missing mouse cursor. if (m_desktop->VideoBuffer() && m_desktop->m_hookdriver) { m_desktop->m_buffer.GrabRegion(rgncache,true); } else { m_desktop->m_buffer.GrabRegion(rgncache,false); } // sf@2002 - v1.1.x - Mouse handling // If one client, send cursor shapes only when the cursor changes. // This is Disabled for now. if( !XRichCursorEnabled==m_desktop->m_server->IsXRichCursorEnabled()) { XRichCursorEnabled=m_desktop->m_server->IsXRichCursorEnabled(); #ifdef DRIVER if (m_desktop->m_videodriver) { if (!XRichCursorEnabled) m_desktop->m_videodriver->HardwareCursor(); else m_desktop->m_videodriver->NoHardwareCursor(); } #endif } if (m_desktop->m_server->IsXRichCursorEnabled() && !m_desktop->m_UltraEncoder_used) { if (m_desktop->m_hcursor != m_desktop->m_hOldcursor || m_desktop->m_buffer.IsShapeCleared()) { m_desktop->m_hOldcursor = m_desktop->m_hcursor; m_desktop->m_buffer.SetCursorPending(TRUE); if (!m_desktop->m_hookdriver) m_desktop->m_buffer.GrabMouse(); // Grab mouse cursor in all cases m_desktop->m_server->UpdateMouse(); rfb::Rect rect; int x = m_desktop->m_cursorpos.tl.x; int w = m_desktop->m_cursorpos.br.x-x; int y = m_desktop->m_cursorpos.tl.y; int h = m_desktop->m_cursorpos.br.y-y; if (ClipRect(&x, &y, &w, &h, m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.tl.y, m_desktop->m_bmrect.br.x-m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.br.y-m_desktop->m_bmrect.tl.y)) { rect.tl.x = x; rect.br.x = x+w; rect.tl.y = y; rect.br.y = y+h; rgncache = rgncache.union_(rect); // vnclog.Print(LL_INTINFO, VNCLOG("7 %i %i %i %i \n"),m_desktop->m_cursorpos.br.x,m_desktop->m_cursorpos.br.y,m_desktop->m_cursorpos.tl.x,m_desktop->m_cursorpos.tl.y); // vnclog.Print(LL_INTINFO, VNCLOG("6 %i %i %i %i \n"),rect.br.x,rect.br.y,rect.tl.x,rect.tl.y); } m_server->UpdateCursorShape(); } } else if (!m_desktop->m_hookdriver)// If several clients, send them all the mouse updates { // Render the mouse //if (!m_desktop->VideoBuffer()) m_desktop->m_buffer.GrabMouse(); if (cursormoved /*&& !m_desktop->m_buffer.IsCursorUpdatePending()*/) { // Inform clients that it has moved m_desktop->m_server->UpdateMouse(); // Get the buffer to fetch the pointer bitmap if (!m_desktop->m_cursorpos.is_empty()) { rfb::Rect rect; int x = m_desktop->m_cursorpos.tl.x; int w = m_desktop->m_cursorpos.br.x-x; int y = m_desktop->m_cursorpos.tl.y; int h = m_desktop->m_cursorpos.br.y-y; if (ClipRect(&x, &y, &w, &h, m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.tl.y, m_desktop->m_bmrect.br.x-m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.br.y-m_desktop->m_bmrect.tl.y)) { rect.tl.x = x; rect.br.x = x+w; rect.tl.y = y; rect.br.y = y+h; rgncache = rgncache.union_(rect); vnclog.Print(LL_INTINFO, VNCLOG("8 %i %i %i %i \n"),m_desktop->m_cursorpos.br.x,m_desktop->m_cursorpos.br.y,m_desktop->m_cursorpos.tl.x,m_desktop->m_cursorpos.tl.y); vnclog.Print(LL_INTINFO, VNCLOG("8 %i %i %i %i \n"),rect.br.x,rect.br.y,rect.tl.x,rect.tl.y); } } } } // SCAN THE CHANGED REGION FOR ACTUAL CHANGES // The hooks return hints as to areas that may have changed. // We check the suggested areas, and just send the ones that // have actually changed. // Note that we deliberately don't check the copyrect destination // here, to reduce the overhead & the likelihood of corrupting the // backbuffer contents. rfb::Region2D checkrgn; rfb::Region2D changedrgn; rfb::Region2D cachedrgn; //Update the backbuffer for the copyrect region if (!clipped_updates.get_copied_region().is_empty()) { rfb::UpdateInfo update_info; rfb::RectVector::const_iterator i; clipped_updates.get_update(update_info); if (!update_info.copied.empty()) { for (i=update_info.copied.begin(); i!=update_info.copied.end(); i++) m_desktop->m_buffer.CopyRect(*i, update_info.copy_delta); } } //Remove the copyrect region from the other updates //checkrgn = rgncache.union_(clipped_updates.get_copied_region()); checkrgn = rgncache.subtract(clipped_updates.get_copied_region()); //make sure the copyrect is checked next update rgncache = clipped_updates.get_copied_region(); //Check all regions for changed and cached parts //This is very cpu intensive, only check once for all viewers if (!checkrgn.is_empty()) m_desktop->m_buffer.CheckRegion(changedrgn,cachedrgn, checkrgn); updates.add_changed(changedrgn); updates.add_cached(cachedrgn); clipped_updates.get_update(m_server->GetUpdateTracker()); } // end mutex lock // Clear the update tracker and region cache an solid clipped_updates.clear(); // screen blanking if (m_desktop->OldPowerOffTimeout!=0) { if (!m_server->BlackAlphaBlending()) { SystemParametersInfo(SPI_SETPOWEROFFACTIVE, 1, NULL, 0); SendMessage(m_desktop->m_hwnd,WM_SYSCOMMAND,SC_MONITORPOWER,(LPARAM)2); if (m_desktop->pbi) (*m_desktop->pbi)(true); } } } // Now wait for more messages to be queued if (!WaitMessage()) { vnclog.Print(LL_INTERR, VNCLOG("WaitMessage() failed\n")); break; } }//peek message else if (msg.message == RFB_SCREEN_UPDATE) { // Process an incoming update event // An area of the screen has changed // ddihook also use RFB_SCREEN_UPDATE // to passe the updates rfb::Rect rect; rect.tl = rfb::Point((SHORT)LOWORD(msg.wParam), (SHORT)HIWORD(msg.wParam)); rect.br = rfb::Point((SHORT)LOWORD(msg.lParam), (SHORT)HIWORD(msg.lParam)); //Buffer coordinates rect.tl.x-=m_desktop->m_ScreenOffsetx; rect.br.x-=m_desktop->m_ScreenOffsetx; rect.tl.y-=m_desktop->m_ScreenOffsety; rect.br.y-=m_desktop->m_ScreenOffsety; // vnclog.Print(LL_INTERR, VNCLOG("REct %i %i %i %i \n"),rect.tl.x,rect.br.x,rect.tl.y,rect.br.y); rect = rect.intersect(m_desktop->m_Cliprect); if (!rect.is_empty()) { rgncache = rgncache.union_(rect); } idle_skip = TRUE; } else if (msg.message == RFB_MOUSE_UPDATE) { // Process an incoming mouse event // Save the cursor ID m_desktop->SetCursor((HCURSOR) msg.wParam); idle_skip = TRUE; } else if (msg.message == WM_QUIT) { break; } else if (msg.message == WM_USER) { // driver dedected a cursor change if (MyGetCursorInfo) { MyCURSORINFO cinfo; cinfo.cbSize=sizeof(MyCURSORINFO); MyGetCursorInfo(&cinfo); m_desktop->SetCursor(cinfo.hCursor); } } else if (msg.message == WM_USER+2) { // Forced idle full screen update rgncache=rgncache.union_(m_desktop->m_Cliprect); } else { // Process any other messages normally TranslateMessage(&msg); DispatchMessage(&msg); idle_skip = TRUE; } }//while m_desktop->SetClipboardActive(FALSE); vnclog.Print(LL_INTINFO, VNCLOG("quitting desktop server thread\n")); // Clear all the hooks and close windows, etc. m_desktop->SetDisableInput(false); m_desktop->Shutdown(); m_server->SingleWindow(false); // Clear the shift modifier keys, now that there are no remote clients vncKeymap::ClearShiftKeys(); // Switch back into our home desktop, under NT (no effect under 9x) vncService::SelectHDESK(home_desktop); g_DesktopThread_running=false; HWND mywin=FindWindow("blackscreen",NULL); if (mywin)PostMessage(mywin,WM_CLOSE, 0, 0); return NULL; }