mirror of https://github.com/quasar/Quasar.git
Refactoring, improvements, and more
Rafactored a reasonably large portion of the Remote Desktop. Added a few interfaces, cleaned up some code, and multiple improvements to the design. Also fully implemented the new custom PictureBox control. Performance gain is more noticable.
This commit is contained in:
parent
d697e32c1e
commit
2d2a66b3d1
|
@ -16,7 +16,11 @@ protected override void Dispose(bool disposing)
|
|||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
|
||||
// Stop running.
|
||||
this.Stop();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,129 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using xServer.Core.Utilities;
|
||||
|
||||
namespace xServer.Controls
|
||||
{
|
||||
public partial class PictureBoxEx : PictureBox
|
||||
public delegate void PictureSizeChangedEventHandler(int width, int height);
|
||||
|
||||
public class PictureSizeChangedEventArgs : EventArgs
|
||||
{
|
||||
public int NewWidth;
|
||||
public int NewHeight;
|
||||
|
||||
public PictureSizeChangedEventArgs(int width, int height)
|
||||
{
|
||||
NewWidth = width;
|
||||
NewHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IRapidPictureBox
|
||||
{
|
||||
bool Running { get; set; }
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
void UpdateImage(Bitmap bmp, bool cloneBitmap = false);
|
||||
|
||||
Image _Image { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom PictureBox Control designed for rapidly-changing images.
|
||||
/// </summary>
|
||||
public partial class PictureBoxEx : PictureBox, IRapidPictureBox
|
||||
{
|
||||
#region IRapidPictureBox Implementation
|
||||
|
||||
public bool Running { get; set; }
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_frameCounter = new FrameCounter();
|
||||
|
||||
_sWatch = Stopwatch.StartNew();
|
||||
|
||||
Running = true;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (_sWatch != null)
|
||||
_sWatch.Stop();
|
||||
|
||||
Running = false;
|
||||
}
|
||||
|
||||
public void UpdateImage(Bitmap bmp, bool cloneBitmap = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
CountFps();
|
||||
|
||||
if ((bmpWidth != bmp.Width) && (bmpHeight != bmp.Height))
|
||||
OnPictureSizeChanged(new PictureSizeChangedEventArgs(bmp.Width, bmp.Height));
|
||||
|
||||
lock (ImgLocker)
|
||||
{
|
||||
if (this._Image != null)
|
||||
{
|
||||
this._Image.Dispose();
|
||||
this._Image = null;
|
||||
}
|
||||
|
||||
this._Image = cloneBitmap ? new Bitmap(bmp, picDesktop.Width, picDesktop.Height) /*resize bitmap*/ : bmp;
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(
|
||||
string.Format(
|
||||
"An unexpected error occurred: {0}\n\nPlease report this as fast as possible here:\\https://github.com/MaxXor/xRAT/issues",
|
||||
ex.Message), "", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// Fields used to keep track of the remote desktop's size.
|
||||
public int bmpWidth { get; private set; }
|
||||
public int bmpHeight { get; private set; }
|
||||
|
||||
// Fields for the FrameCounter.
|
||||
public FrameCounter _frameCounter;
|
||||
private Stopwatch _sWatch;
|
||||
|
||||
public PictureBoxEx()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
//this.DoubleBuffered = true;
|
||||
this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
|
||||
|
||||
_frameCounter = new FrameCounter();
|
||||
}
|
||||
|
||||
|
||||
#region Events
|
||||
|
||||
public event PictureSizeChangedEventHandler PictureSizeChanged;
|
||||
|
||||
protected virtual void OnPictureSizeChanged(PictureSizeChangedEventArgs e)
|
||||
{
|
||||
PictureSizeChangedEventHandler handler = PictureSizeChanged;
|
||||
if (handler != null)
|
||||
handler(e.NewWidth, e.NewHeight);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
protected override CreateParams CreateParams
|
||||
{
|
||||
get
|
||||
|
@ -28,7 +136,42 @@ protected override CreateParams CreateParams
|
|||
|
||||
protected override void OnPaint(PaintEventArgs pe)
|
||||
{
|
||||
base.OnPaint(pe);
|
||||
lock (ImgLocker)
|
||||
{
|
||||
if (this._Image != null)
|
||||
{
|
||||
pe.Graphics.DrawImage(this._Image, this.Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void CountFps()
|
||||
{
|
||||
var deltaTime = (float)_sWatch.Elapsed.TotalSeconds;
|
||||
_sWatch = Stopwatch.StartNew();
|
||||
|
||||
_frameCounter.Update(deltaTime);
|
||||
}
|
||||
|
||||
private readonly object ImgLocker = new object();
|
||||
/// <summary>
|
||||
/// Provides thread-safe access to the PictureBox's image.
|
||||
/// </summary>
|
||||
public Image _Image
|
||||
{
|
||||
get
|
||||
{
|
||||
return picDesktop.Image;
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (ImgLocker)
|
||||
{
|
||||
picDesktop.Image = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +1,36 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace xServer.Core.Utilities
|
||||
{
|
||||
public class FrameUpdatedEventArgs : EventArgs
|
||||
{
|
||||
public float CurrentFramesPerSecond { get; private set; }
|
||||
|
||||
public FrameUpdatedEventArgs(float _CurrentFramesPerSecond)
|
||||
{
|
||||
CurrentFramesPerSecond = _CurrentFramesPerSecond;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void FrameUpdatedEventHandler(FrameUpdatedEventArgs e);
|
||||
|
||||
public class FrameCounter
|
||||
{
|
||||
public long TotalFrames { get; private set; }
|
||||
public float TotalSeconds { get; private set; }
|
||||
public float AverageFramesPerSecond { get; private set; }
|
||||
public float CurrentFramesPerSecond { get; private set; }
|
||||
|
||||
public const int MAXIMUM_SAMPLES = 100;
|
||||
|
||||
private Queue<float> _sampleBuffer = new Queue<float>();
|
||||
|
||||
public event FrameUpdatedEventHandler FrameUpdated;
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
CurrentFramesPerSecond = 1.0f / deltaTime;
|
||||
float CurrentFramesPerSecond = 1.0f / deltaTime;
|
||||
|
||||
_sampleBuffer.Enqueue(CurrentFramesPerSecond);
|
||||
|
||||
|
@ -30,8 +44,17 @@ public void Update(float deltaTime)
|
|||
AverageFramesPerSecond = CurrentFramesPerSecond;
|
||||
}
|
||||
|
||||
OnFrameUpdated(new FrameUpdatedEventArgs(AverageFramesPerSecond));
|
||||
|
||||
TotalFrames++;
|
||||
TotalSeconds += deltaTime;
|
||||
}
|
||||
|
||||
protected virtual void OnFrameUpdated(FrameUpdatedEventArgs e)
|
||||
{
|
||||
FrameUpdatedEventHandler handler = FrameUpdated;
|
||||
if (handler != null)
|
||||
handler(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
@ -17,8 +16,7 @@ public partial class FrmRemoteDesktop : Form
|
|||
private readonly Client _connectClient;
|
||||
private bool _enableMouseInput;
|
||||
private bool _started;
|
||||
private FrameCounter _frameCounter;
|
||||
private Stopwatch _sWatch;
|
||||
|
||||
private int _screenWidth;
|
||||
private int _screenHeight;
|
||||
|
||||
|
@ -31,18 +29,20 @@ public FrmRemoteDesktop(Client c)
|
|||
_connectClient = c;
|
||||
_connectClient.Value.FrmRdp = this;
|
||||
InitializeComponent();
|
||||
|
||||
picDesktop.PictureSizeChanged += picDesktop_PictureSizeChanged;
|
||||
}
|
||||
|
||||
private void FrmRemoteDesktop_Load(object sender, EventArgs e)
|
||||
{
|
||||
this.Text = WindowHelper.GetWindowTitle("Remote Desktop", _connectClient);
|
||||
|
||||
panelTop.Left = (this.Width/2) - (panelTop.Width/2);
|
||||
panelTop.Left = (this.Width / 2) - (panelTop.Width / 2);
|
||||
|
||||
btnHide.Left = (panelTop.Width/2) - (btnHide.Width/2);
|
||||
btnHide.Left = (panelTop.Width / 2) - (btnHide.Width / 2);
|
||||
|
||||
btnShow.Location = new Point(377, 0);
|
||||
btnShow.Left = (this.Width/2) - (btnShow.Width/2);
|
||||
btnShow.Left = (this.Width / 2) - (btnShow.Width / 2);
|
||||
|
||||
if (_connectClient.Value != null)
|
||||
new Core.Packets.ServerPackets.GetMonitors().Execute(_connectClient);
|
||||
|
@ -50,7 +50,7 @@ private void FrmRemoteDesktop_Load(object sender, EventArgs e)
|
|||
|
||||
public void ProcessScreens(object state)
|
||||
{
|
||||
while (true)
|
||||
while (true && picDesktop != null && !picDesktop.IsDisposed && !picDesktop.Disposing)
|
||||
{
|
||||
GetDesktopResponse packet;
|
||||
lock (ProcessingScreensQueue)
|
||||
|
@ -68,21 +68,36 @@ public void ProcessScreens(object state)
|
|||
}
|
||||
|
||||
if (_connectClient.Value.StreamCodec == null)
|
||||
_connectClient.Value.StreamCodec = new UnsafeStreamCodec(packet.Quality, packet.Monitor, packet.Resolution);
|
||||
|
||||
if (_connectClient.Value.StreamCodec.ImageQuality != packet.Quality || _connectClient.Value.StreamCodec.Monitor != packet.Monitor
|
||||
|| _connectClient.Value.StreamCodec.Resolution != packet.Resolution)
|
||||
{
|
||||
if (_connectClient.Value.StreamCodec != null)
|
||||
_connectClient.Value.StreamCodec = new UnsafeStreamCodec(packet.Quality, packet.Monitor, packet.Resolution);
|
||||
}
|
||||
else if (_connectClient.Value.StreamCodec.ImageQuality != packet.Quality || _connectClient.Value.StreamCodec.Monitor != packet.Monitor)
|
||||
{
|
||||
if (string.Compare(_connectClient.Value.StreamCodec.Resolution, packet.Resolution, StringComparison.InvariantCultureIgnoreCase) != 0)
|
||||
{
|
||||
_connectClient.Value.StreamCodec.Dispose();
|
||||
}
|
||||
|
||||
_connectClient.Value.StreamCodec = new UnsafeStreamCodec(packet.Quality, packet.Monitor, packet.Resolution);
|
||||
}
|
||||
|
||||
using (MemoryStream ms = new MemoryStream(packet.Image))
|
||||
{
|
||||
if (_connectClient.Value.FrmRdp != null)
|
||||
_connectClient.Value.FrmRdp.UpdateImage(_connectClient.Value.StreamCodec.DecodeData(ms), true);
|
||||
try
|
||||
{
|
||||
// Update the new image from the packet data.
|
||||
picDesktop.UpdateImage(_connectClient.Value.StreamCodec.DecodeData(ms), true);
|
||||
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
if (picDesktop != null && !picDesktop.IsDisposed && picDesktop._Image != null)
|
||||
{
|
||||
picDesktop.Invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
|
||||
packet.Image = null;
|
||||
|
@ -93,7 +108,7 @@ public void AddMonitors(int montiors)
|
|||
{
|
||||
try
|
||||
{
|
||||
cbMonitors.Invoke((MethodInvoker) delegate
|
||||
cbMonitors.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
for (int i = 0; i < montiors; i++)
|
||||
cbMonitors.Items.Add(string.Format("Monitor {0}", i + 1));
|
||||
|
@ -112,73 +127,27 @@ public void AddMonitors(int montiors)
|
|||
}
|
||||
}
|
||||
|
||||
private void CountFps()
|
||||
// Update on frame change.
|
||||
private void _frameCounter_FrameUpdated(FrameUpdatedEventArgs e)
|
||||
{
|
||||
var deltaTime = (float)_sWatch.Elapsed.TotalSeconds;
|
||||
_sWatch = Stopwatch.StartNew();
|
||||
|
||||
_frameCounter.Update(deltaTime);
|
||||
|
||||
UpdateFps(_frameCounter.AverageFramesPerSecond);
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
this.Text = string.Format("{0} - FPS: {1}", WindowHelper.GetWindowTitle("Remote Desktop", _connectClient), e.CurrentFramesPerSecond.ToString("0.00"));
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateFps(float fps)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
this.Text = string.Format("{0} - FPS: {1}", WindowHelper.GetWindowTitle("Remote Desktop", _connectClient), fps.ToString("0.00"));
|
||||
});
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateScreenResolution(int width, int height)
|
||||
private void picDesktop_PictureSizeChanged(int width, int height)
|
||||
{
|
||||
_screenWidth = width;
|
||||
_screenHeight = height;
|
||||
}
|
||||
|
||||
public void UpdateImage(Bitmap bmp, bool cloneBitmap = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
CountFps();
|
||||
UpdateScreenResolution(bmp.Width, bmp.Height);
|
||||
picDesktop.Invoke((MethodInvoker) delegate
|
||||
{
|
||||
// get old image to dispose it correctly
|
||||
var oldImage = picDesktop.Image;
|
||||
|
||||
picDesktop.SuspendLayout();
|
||||
picDesktop.Image = cloneBitmap ? new Bitmap(bmp, picDesktop.Width, picDesktop.Height) /*resize bitmap*/ : bmp;
|
||||
picDesktop.ResumeLayout();
|
||||
|
||||
if (oldImage != null)
|
||||
oldImage.Dispose();
|
||||
});
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(
|
||||
string.Format(
|
||||
"An unexpected error occurred: {0}\n\nPlease report this as fast as possible here:\\https://github.com/MaxXor/xRAT/issues",
|
||||
ex.Message), "", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleControls(bool t)
|
||||
{
|
||||
_started = !t;
|
||||
try
|
||||
{
|
||||
this.Invoke((MethodInvoker) delegate
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
btnStart.Enabled = t;
|
||||
btnStop.Enabled = !t;
|
||||
|
@ -194,16 +163,16 @@ private void FrmRemoteDesktop_FormClosing(object sender, FormClosingEventArgs e)
|
|||
{
|
||||
if (_started)
|
||||
new Core.Packets.ServerPackets.GetDesktop(0, 0, RemoteDesktopAction.Stop).Execute(_connectClient);
|
||||
if (_sWatch != null)
|
||||
_sWatch.Stop();
|
||||
if (!picDesktop.IsDisposed && !picDesktop.Disposing)
|
||||
picDesktop.Dispose();
|
||||
if (_connectClient.Value != null)
|
||||
_connectClient.Value.FrmRdp = null;
|
||||
}
|
||||
|
||||
private void FrmRemoteDesktop_Resize(object sender, EventArgs e)
|
||||
{
|
||||
panelTop.Left = (this.Width/2) - (panelTop.Width/2);
|
||||
btnShow.Left = (this.Width/2) - (btnShow.Width/2);
|
||||
panelTop.Left = (this.Width / 2) - (panelTop.Width / 2);
|
||||
btnShow.Left = (this.Width / 2) - (btnShow.Width / 2);
|
||||
}
|
||||
|
||||
private void btnStart_Click(object sender, EventArgs e)
|
||||
|
@ -215,11 +184,13 @@ private void btnStart_Click(object sender, EventArgs e)
|
|||
return;
|
||||
}
|
||||
|
||||
_frameCounter = new FrameCounter();
|
||||
_sWatch = Stopwatch.StartNew();
|
||||
|
||||
ToggleControls(false);
|
||||
|
||||
picDesktop.Start();
|
||||
|
||||
// Subscribe to the new frame counter.
|
||||
picDesktop._frameCounter.FrameUpdated += _frameCounter_FrameUpdated;
|
||||
|
||||
new Core.Packets.ServerPackets.GetDesktop(barQuality.Value, cbMonitors.SelectedIndex, RemoteDesktopAction.Start).Execute(_connectClient);
|
||||
}
|
||||
|
||||
|
@ -227,7 +198,11 @@ private void btnStop_Click(object sender, EventArgs e)
|
|||
{
|
||||
new Core.Packets.ServerPackets.GetDesktop(0, 0, RemoteDesktopAction.Stop).Execute(_connectClient);
|
||||
ToggleControls(true);
|
||||
_sWatch.Stop();
|
||||
|
||||
picDesktop.Stop();
|
||||
|
||||
// Unsubscribe from the frame counter. It will be re-created when starting again.
|
||||
picDesktop._frameCounter.FrameUpdated -= _frameCounter_FrameUpdated;
|
||||
}
|
||||
|
||||
private void barQuality_Scroll(object sender, EventArgs e)
|
||||
|
|
Loading…
Reference in New Issue