Ejemplo n.º 1
0
void *
vncDesktopThread::run_undetached(void *arg)
{
	// Save the thread's "home" desktop, under NT (no effect under 9x)
	HDESK home_desktop = GetThreadDesktop(GetCurrentThreadId());

	// Attempt to initialise and return success or failure
	if (!m_desktop->Startup())
	{
		vncService::SelectHDESK(home_desktop);
		ReturnVal(FALSE);
		return NULL;
	}

  // Grab the initial display contents
  // *** m_desktop->m_buffer.GrabRegion(m_desktop->m_bmrect);
  // *** m_desktop->m_buffer.Clear(m_desktop->m_bmrect);

	// Succeeded to initialise ok
	ReturnVal(TRUE);

	// START PROCESSING DESKTOP MESSAGES

	// 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_bmrect);
	clipped_updates.enable_copyrect(true);

	// 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
	rfb::Region2D rgncache = m_desktop->m_bmrect;

	// The previous cursor position is stored, to allow us to erase the
	// old instance whenever it moves.
	rfb::Point oldcursorpos;

	// Set the hook thread to a high priority
	// *** set_priority(omni_thread::PRIORITY_HIGH);

	BOOL idle_skip = TRUE;
	ULONG idle_skip_count = 0;
	MSG msg;
	while (TRUE)
	{
		if (!PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
			//
			// - MESSAGE QUEUE EMPTY
			// Whenever the message queue becomes empty, we check to see whether
			// there are updates to be passed to clients.
			if (idle_skip) {
				idle_skip = FALSE;
				if (idle_skip_count++ < 4) {
					Sleep(5);
					continue;
				}
			}
			idle_skip_count = 0;

			// Clear the triggered flag
			m_desktop->m_update_triggered = FALSE;

			//
			// CHECK SCREEN FORMAT
			// First, we must check that the screen hasnt changed too much.
			if (m_desktop->m_displaychanged || !vncService::InputDesktopSelected())
			{
				rfbServerInitMsg oldscrinfo = m_desktop->m_scrinfo;
				m_desktop->m_displaychanged = FALSE;

				// Attempt to close the old hooks
				if (!m_desktop->Shutdown())
				{
					m_server->KillAuthClients();
					break;
				}

				// Now attempt to re-install them!
				if (!m_desktop->Startup())
				{
					m_server->KillAuthClients();
					break;
				}

				// Check that the screen info hasn't 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_desktop->m_scrinfo.framebufferWidth,
				//	m_desktop->m_scrinfo.framebufferHeight,
				//	m_desktop->m_scrinfo.format.bitsPerPixel);
				if ((m_desktop->m_scrinfo.framebufferWidth != oldscrinfo.framebufferWidth) ||
					(m_desktop->m_scrinfo.framebufferHeight != oldscrinfo.framebufferHeight))
				{
					m_server->KillAuthClients();
					break;
				} else if (memcmp(&m_desktop->m_scrinfo.format, &oldscrinfo.format, sizeof(rfbPixelFormat)) != 0)
				{
					m_server->UpdateLocalFormat();
				}

				// Adjust the UpdateTracker clip region
				updates.set_clip_region(m_desktop->m_bmrect);

				// Add a full screen update to all the clients
				rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_bmrect));
				m_server->UpdatePalette();
			}
	
			//
			// CALCULATE CHANGES
			//

			if (m_desktop->m_server->UpdateWanted())
			{
				// POLL PROBLEM AREAS
				// We add specific areas of the screen to the region cache,
				// causing them to be fetched for processing.
				if (m_desktop->m_server->PollFullScreen())
				{
					rfb::Rect rect = m_desktop->m_qtrscreen;
					rect = rect.translate(rfb::Point(0, m_desktop->m_pollingcycle * m_desktop->m_qtrscreen.br.y));
					rgncache = rgncache.union_(rfb::Region2D(rect));
					m_desktop->m_pollingcycle = (m_desktop->m_pollingcycle + 1) % 4;
				}
				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);
					}
				}

				// 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.

				// 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);
				}
				if (cursormoved) {
					if (!m_desktop->m_cursorpos.is_empty())
						rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_cursorpos));
				}

				{
					// 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
					m_desktop->CalcCopyRects(updates);

					// GRAB THE DISPLAY
					// Fetch data from the display to our display cache.
					m_desktop->m_buffer.GrabRegion(rgncache);
				  // Render the mouse
				  m_desktop->m_buffer.GrabMouse();
					if (cursormoved) {
						// 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())
							rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_cursorpos));
					}

					// 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 = rgncache.subtract(clipped_updates.get_copied_region());
					rgncache = clipped_updates.get_copied_region();
					rfb::Region2D changedrgn;
					m_desktop->m_buffer.CheckRegion(changedrgn, checkrgn);

					// FLUSH UPDATES TO CLIENTS
					// Add the bits that have really changed to their update regions
					// Note that the cursor is NOT included - they must do that
					// themselves, for the reasons above.
					// This call implicitly kicks clients to update themselves

					updates.add_changed(changedrgn);
					clipped_updates.get_update(m_server->GetUpdateTracker());
				}

				// Clear the update tracker and region cache
				clipped_updates.clear();
			}

			// Now wait for more messages to be queued
			if (!WaitMessage()) {
				//vnclog.Print(LL_INTERR, VNCLOG("WaitMessage() failed\n"));
				break;
			}
		} else if (msg.message == RFB_SCREEN_UPDATE) {
			// Process an incoming update event

			// An area of the screen has changed
			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));
			rect = rect.intersect(m_desktop->m_bmrect);
			if (!rect.is_empty()) {
				rgncache = rgncache.union_(rfb::Region2D(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 {
			// Process any other messages normally
			DispatchMessage(&msg);

			idle_skip = TRUE;
		}
	}

	m_desktop->SetClipboardActive(FALSE);
	
	//vnclog.Print(LL_INTINFO, VNCLOG("quitting desktop server thread\n"));

	// Clear all the hooks and close windows, etc.
	m_desktop->Shutdown();

	// 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);

	return NULL;
}
Ejemplo n.º 2
0
void vncDesktopThread::do_polling(HANDLE& threadHandle, rfb::Region2D& rgncache, int& fullpollcounter, bool cursormoved)
{
	// POLL PROBLEM AREAS
	// We add specific areas of the screen to the region cache,
	// causing them to be fetched for processing.
	// if can_be_hooked==false, hooking is temp disabled, use polling

	if (m_desktop->SetHook && g_obIPC.listall()!=NULL && m_desktop->can_be_hooked) 
	{
		DWORD dwTId(0);
		if (threadHandle==NULL) threadHandle = CreateThread(NULL, 0, hookwatch, this, 0, &dwTId);
		if (Handle_Ringbuffer(g_obIPC.listall(),rgncache)) return;
	}
	DWORD lTime = timeGetTime();

	m_desktop->m_buffer.SetAccuracy(m_desktop->m_server->TurboMode() ? 8 : 4); 

	if (cursormoved)
		m_lLastMouseMoveTime = lTime;
	
	if ((m_desktop->m_server->PollFullScreen() && !cursormoved) || (!m_desktop->can_be_hooked && !cursormoved))
	{
		int timeSinceLastMouseMove = lTime - m_lLastMouseMoveTime;
		if (timeSinceLastMouseMove > 15) // 150 ms pause after a Mouse move 
		{
			++fullpollcounter;
			// THIS FUNCTION IS A PIG. It uses too much CPU on older machines (PIII, P4)
			if (m_desktop->FastDetectChanges(rgncache, m_desktop->GetSize(), 0, true)) capture=false;
			// force full screen scan every three seconds after the mouse stops moving
			if (fullpollcounter > 20) 
			{
				rgncache.assign_union(m_desktop->m_Cliprect);
				fullpollcounter = 0;
			}
		}
	}
		
    HWND hWndToPoll = 0;
	if (m_desktop->m_server->PollForeground() || !m_desktop->can_be_hooked)
	{
		// Get the window rectangle for the currently selected window
		hWndToPoll = GetForegroundWindow();
		if (hWndToPoll != NULL)
			 PollWindow(rgncache, hWndToPoll);
		
	}
	
	if (m_desktop->m_server->PollUnderCursor() || !m_desktop->can_be_hooked)
	{
		// Find the mouse position
		POINT mousepos;
		if (GetCursorPos(&mousepos))
		{
			mousepos.x=g_dpi.UnscaleX(mousepos.x);
			mousepos.y=g_dpi.UnscaleY(mousepos.y);
			// Find the window under the mouse
			HWND hwnd = WindowFromPoint(mousepos);
            // exclude the foreground window (done above) and desktop
			if (hwnd != NULL && hwnd != hWndToPoll && hwnd != GetDesktopWindow())
				 PollWindow(rgncache, hwnd);

		}
	}
}