public void Disconnect() { // Cancel read thread m_cancelTokenSource?.Cancel(); // There may not be any received messages and it may be blocked by Read. // Therefore, send FramebufferUpdate so that the client sends a message. m_client?.WriteFramebufferUpdateRequest(); // Wait for completion or timeout (5 second). m_readTask?.Wait(5 * 1000); // Disconnect m_client?.DisconnectVnc(); // Execute to draw this control black. // Without this, the screen will not be updated and the VNC image will remain. NativeMethods.InvalidateRect(m_handle, (IntPtr)0, false); }
protected override void OnPaint(PaintEventArgs e) { if (DesignMode) { e.Graphics.DrawRectangle(Pens.DarkGray, 0, 0, this.Width - 1, this.Height - 1); } else { if (m_client != null && m_client.Connected) { if (m_last.Enable) { m_client.WritePointerEvent(m_last.Mask, (UInt16)m_last.X, (UInt16)m_last.Y); m_lastPointerSendDt = DateTime.Now; m_last.Enable = false; } // NearestNeighbor is the fastest. e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; // At the time of connection, the background black is left, so erase it if (!m_prevConnected) { m_prevConnected = true; e.Graphics.Clear(this.BackColor); } // Lock to access below. // - m_client.InternalCanvas // - m_encodeList lock (m_client.CanvasLock) { BitmapConverter.ToBitmap(m_client.InternalCanvas, (Bitmap)m_image); // When the size changes, redraw it all. // Or if the focus is lost, redraw it all. if (m_prevSize.Width != this.Width || m_prevSize.Height != this.Height || m_needsRedraw) { m_prevSize.Width = this.Width; m_prevSize.Height = this.Height; m_needsRedraw = false; // I could not draw correctly if the size was not an integer ratio. // Therefore, find the integer ratio that the denominator becomes 10 or less. m_xZoom = new Fraction(this.Width, m_client.ServerInitBody.FramebufferWidth, 10); m_yZoom = new Fraction(this.Height, m_client.ServerInitBody.FramebufferHeight, 10); int width = (int)(m_client.ServerInitBody.FramebufferWidth * m_xZoom.Numerator / m_xZoom.Denominator); int height = (int)(m_client.ServerInitBody.FramebufferHeight * m_yZoom.Numerator / m_yZoom.Denominator); // Redraw all e.Graphics.DrawImage(m_image, 0, 0, width, height); } // If the size is the same, draw only the difference. else { foreach (var list in m_encodeList) { foreach (var v in list) { // To draw correctly, I calculate drawing source rectangle and drawing destination rectangle. // ex. // Framebuffer = 640x480 // Control = 320x240 // Source Rectangle(x,y,w,h) = (101, 101, 10, 10) // => (100, 100, 12, 12) (Convert to be divisible) // Dest Rectangle(x,y,w,h) => (50, 50, 5, 5) int newX = (int)(v.X / m_xZoom.Denominator) * m_xZoom.Denominator; int newY = (int)(v.Y / m_yZoom.Denominator) * m_yZoom.Denominator; int newW = (int)(Math.Ceiling((double)(v.Width + v.X - newX) / m_xZoom.Denominator) * m_xZoom.Denominator); int newH = (int)(Math.Ceiling((double)(v.Height + v.Y - newY) / m_yZoom.Denominator) * m_yZoom.Denominator); int xpos = newX * m_xZoom.Numerator / m_xZoom.Denominator; int ypos = newY * m_yZoom.Numerator / m_yZoom.Denominator; int width = newW * m_xZoom.Numerator / m_xZoom.Denominator; int height = newH * m_yZoom.Numerator / m_yZoom.Denominator; e.Graphics.DrawImage(m_image, new Rectangle(xpos, ypos, width, height), newX, newY, newW, newH, GraphicsUnit.Pixel); } } m_encodeList.Clear(); } } m_client.WriteFramebufferUpdateRequest(); } else { m_prevConnected = false; e.Graphics.FillRectangle(Brushes.Black, 0, 0, this.Width, this.Height); } } }