SharpDisplay: Migrating to new robust client scheme. default tip
authorsl
Thu, 01 Jan 2015 23:35:49 +0100
changeset 4055715aefd2bcc
parent 404 7b7fad708159
SharpDisplay: Migrating to new robust client scheme.
.editorconfig
GUI/SharpDisplay.cs
GUI/SharpDisplayClient.cs
GUI/SharpDisplayInterface.cs
OpenHardwareMonitor.csproj
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.editorconfig	Thu Jan 01 23:35:49 2015 +0100
     1.3 @@ -0,0 +1,12 @@
     1.4 +; Top-most EditorConfig file
     1.5 +root = true
     1.6 +
     1.7 +; Windows-style newlines
     1.8 +[*]
     1.9 +end_of_line = crlf
    1.10 +
    1.11 +; 4-column tab indentation
    1.12 +[*.cs]
    1.13 +indent_style = tab
    1.14 +indent_size = 4
    1.15 +
     2.1 --- a/GUI/SharpDisplay.cs	Mon Sep 22 21:59:11 2014 +0200
     2.2 +++ b/GUI/SharpDisplay.cs	Thu Jan 01 23:35:49 2015 +0100
     2.3 @@ -25,19 +25,19 @@
     2.4  
     2.5  namespace OpenHardwareMonitor.GUI
     2.6  {
     2.7 -    public class SharpDisplay : ICallback, IDisposable
     2.8 +    public class SharpDisplay : IDisposable
     2.9      {
    2.10          private IComputer computer;
    2.11          private PersistentSettings settings;
    2.12          private UnitManager unitManager;
    2.13          private List<SensorSharpDisplay> iSensors = new List<SensorSharpDisplay>();
    2.14 -        private global::SharpDisplay.Client iClient;
    2.15 -        TextField iTextFieldTop;
    2.16 -        TextField iTextFieldBottom;
    2.17 -        TextField iTextFieldTopRight;
    2.18 -        TextField iTextFieldBottomRight;
    2.19 +        private global::SharpDisplay.DisplayClient iClient;
    2.20 +        DataField iTextFieldTop;
    2.21 +		DataField iTextFieldBottom;
    2.22 +		DataField iTextFieldTopRight;
    2.23 +		DataField iTextFieldBottomRight;
    2.24  
    2.25 -        TextField[] iTextFields;
    2.26 +		DataField[] iTextFields;
    2.27  
    2.28          private int iNextSensorToDisplay = 0;
    2.29          private int iTickCounter = 0;
    2.30 @@ -53,32 +53,18 @@
    2.31  
    2.32              //Connect our client
    2.33              //Instance context is then managed by our client class
    2.34 -            iClient = new global::SharpDisplay.Client(this);
    2.35 +            iClient = new global::SharpDisplay.DisplayClient();
    2.36              //
    2.37 -            iTextFieldTop = new TextField(0);
    2.38 -            iTextFieldBottom = new TextField(1);
    2.39 -            iTextFieldTopRight = new TextField(2, "", ContentAlignment.MiddleRight);
    2.40 -            iTextFieldBottomRight = new TextField(3, "", ContentAlignment.MiddleRight);
    2.41 -
    2.42 -            iTextFields = new TextField[] { iTextFieldTop, iTextFieldBottom };
    2.43 -
    2.44 +			iTextFieldTop = new DataField(0);
    2.45 +			iTextFieldBottom = new DataField(1);
    2.46 +			iTextFieldTopRight = new DataField(2, "", ContentAlignment.MiddleRight);
    2.47 +			iTextFieldBottomRight = new DataField(3, "", ContentAlignment.MiddleRight);
    2.48 +			//
    2.49 +			iClient.Open();
    2.50 +			iClient.SetName("Open Hardware Monitor");
    2.51 +			CreateFields();
    2.52          }
    2.53  
    2.54 -        //From ICallback
    2.55 -        public void OnConnected()
    2.56 -        {
    2.57 -            //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
    2.58 -            //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
    2.59 -            //MessageBox.Show("OnConnected()", "Client");
    2.60 -        }
    2.61 -
    2.62 -        //From ICallback
    2.63 -        public void OnCloseOrder()
    2.64 -        {
    2.65 -            iClient.Close();
    2.66 -        }
    2.67 -
    2.68 -
    2.69          private void HardwareRemoved(IHardware hardware)
    2.70          {
    2.71              hardware.SensorAdded -= new SensorEventHandler(SensorAdded);
    2.72 @@ -123,6 +109,27 @@
    2.73  
    2.74          }
    2.75  
    2.76 +		private void CreateFields()
    2.77 +		{
    2.78 +			if (iPacked)
    2.79 +            {
    2.80 +                //We just switched to packed mode                    
    2.81 +                //Make sure our layout is proper
    2.82 +                TableLayout layout = new TableLayout(2, 2);
    2.83 +                iClient.SetLayout(layout);
    2.84 +				iTextFields = new DataField[] { iTextFieldTop, iTextFieldBottom, iTextFieldTopRight, iTextFieldBottomRight };
    2.85 +				iClient.CreateFields(iTextFields);
    2.86 +            }
    2.87 +            else
    2.88 +            {
    2.89 +                //Non packed mode
    2.90 +                TableLayout layout = new TableLayout(1, 2);
    2.91 +                iClient.SetLayout(layout);
    2.92 +				iTextFields = new DataField[] { iTextFieldTop, iTextFieldBottom };
    2.93 +				iClient.CreateFields(iTextFields);
    2.94 +            }
    2.95 +		}
    2.96 +
    2.97          public void Redraw(bool aPacked, bool aDisplayTime)
    2.98          {
    2.99              const int KNumberOfTickBeforeSwitch = 4;
   2.100 @@ -141,19 +148,8 @@
   2.101                      //Remember mode
   2.102                      iPacked = aPacked;
   2.103  
   2.104 -                    if (iPacked)
   2.105 -                    {
   2.106 -                        //We just switched to packed mode                    
   2.107 -                        //Make sure our layout is proper
   2.108 -                        TableLayout layout = new TableLayout(2, 2);
   2.109 -                        iClient.SetLayout(layout);
   2.110 -                    }
   2.111 -                    else
   2.112 -                    {
   2.113 -                        //Non packed mode
   2.114 -                        TableLayout layout = new TableLayout(1, 2);
   2.115 -                        iClient.SetLayout(layout);
   2.116 -                    }
   2.117 +					CreateFields();
   2.118 +
   2.119                  }
   2.120              }
   2.121  
   2.122 @@ -169,7 +165,7 @@
   2.123                      //First slot is taken by time display
   2.124                      count++;
   2.125                      iTextFieldTop.Text = time;
   2.126 -                    iClient.SetText(iTextFieldTop);
   2.127 +                    iClient.SetField(iTextFieldTop);
   2.128                  }
   2.129  
   2.130                  if (aPacked)
   2.131 @@ -180,22 +176,22 @@
   2.132                      if (count == 1)
   2.133                      {
   2.134                          iTextFieldTop.Text = packedText;
   2.135 -                        iClient.SetText(iTextFieldTop);
   2.136 +						iClient.SetField(iTextFieldTop);
   2.137                      }
   2.138                      else if (count == 2)
   2.139                      {
   2.140                          iTextFieldBottom.Text = packedText;
   2.141 -                        iClient.SetText(iTextFieldBottom);
   2.142 +						iClient.SetField(iTextFieldBottom);
   2.143                      }
   2.144                      else if (count == 3)
   2.145                      {
   2.146                          iTextFieldTopRight.Text = packedText;
   2.147 -                        iClient.SetText(iTextFieldTopRight);
   2.148 +						iClient.SetField(iTextFieldTopRight);
   2.149                      }
   2.150                      else if (count == 4)
   2.151                      {
   2.152                          iTextFieldBottomRight.Text = packedText;
   2.153 -                        iClient.SetText(iTextFieldBottomRight);
   2.154 +						iClient.SetField(iTextFieldBottomRight);
   2.155                      }
   2.156                  }
   2.157              }
   2.158 @@ -345,7 +341,7 @@
   2.159              //iServer.SendMessage("set-vfd-text:" + aUpperLine + "\n" + aLowerLine);
   2.160              iTextFieldTop.Text = aUpperLine;
   2.161              iTextFieldBottom.Text = aLowerLine;
   2.162 -            iClient.SetTexts(iTextFields);
   2.163 +            iClient.SetFields(iTextFields);
   2.164  
   2.165          }
   2.166  
     3.1 --- a/GUI/SharpDisplayClient.cs	Mon Sep 22 21:59:11 2014 +0200
     3.2 +++ b/GUI/SharpDisplayClient.cs	Thu Jan 01 23:35:49 2015 +0100
     3.3 @@ -1,207 +1,64 @@
     3.4 -/*
     3.5 - 
     3.6 -  This Source Code Form is subject to the terms of the Mozilla Public
     3.7 -  License, v. 2.0. If a copy of the MPL was not distributed with this
     3.8 -  file, You can obtain one at http://mozilla.org/MPL/2.0/.
     3.9 - 
    3.10 -  Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
    3.11 -	
    3.12 -*/
    3.13 -
    3.14 +
    3.15  using System;
    3.16  using System.Collections.Generic;
    3.17 -using System.Drawing;
    3.18 +using System.Linq;
    3.19  using System.Text;
    3.20 -using System.Diagnostics;
    3.21 +using System.Threading.Tasks;
    3.22  using System.Windows.Forms;
    3.23 -using System.Windows;
    3.24 -using OpenHardwareMonitor.Hardware;
    3.25 -using OpenHardwareMonitor.Utilities;
    3.26 -using System.Runtime.InteropServices;
    3.27 -using UacHelpers;
    3.28 -//
    3.29 +using SharpDisplay;
    3.30  using System.ServiceModel;
    3.31 -using System.Runtime.Serialization;
    3.32 -using SharpDisplay;
    3.33 +using System.ServiceModel.Channels;
    3.34 +
    3.35  
    3.36  namespace SharpDisplay
    3.37  {
    3.38 -
    3.39 -
    3.40 -
    3.41 -    /// <summary>
    3.42 -    /// For client to specify a specific layout.
    3.43 -    /// </summary>
    3.44 -    [DataContract]
    3.45 -    public class TableLayout
    3.46 -    {
    3.47 -        public TableLayout()
    3.48 -        {
    3.49 -            Columns = new List<ColumnStyle>();
    3.50 -            Rows = new List<RowStyle>();
    3.51 -            Cells = new List<DataField>();
    3.52 -        }
    3.53 -
    3.54 -        public TableLayout(int aColumnCount, int aRowCount)
    3.55 -        {
    3.56 -            Columns = new List<ColumnStyle>();
    3.57 -            Rows = new List<RowStyle>();
    3.58 -
    3.59 -            for (int i = 0; i < aColumnCount; i++)
    3.60 -            {
    3.61 -                Columns.Add(new ColumnStyle(SizeType.Percent, 100 / aColumnCount));
    3.62 -            }
    3.63 -
    3.64 -            for (int i = 0; i < aRowCount; i++)
    3.65 -            {
    3.66 -                Rows.Add(new RowStyle(SizeType.Percent, 100 / aRowCount));
    3.67 -            }
    3.68 -        }
    3.69 -
    3.70 -        [DataMember]
    3.71 -        public List<DataField> Cells { get; set; }
    3.72 -
    3.73 -        [DataMember]
    3.74 -        public List<ColumnStyle> Columns { get; set; }
    3.75 -
    3.76 -        [DataMember]
    3.77 -        public List<RowStyle> Rows { get; set; }
    3.78 -
    3.79 -    }
    3.80 -
    3.81      /// <summary>
    3.82      ///
    3.83      /// </summary>
    3.84 -    [DataContract]
    3.85 -    public class DataField
    3.86 +    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
    3.87 +    public class Callback : ICallback, IDisposable
    3.88      {
    3.89 -        [DataMember]
    3.90 -        public int Column { get; set; }
    3.91 +		private DisplayClient DisplayClient { get; set; }
    3.92  
    3.93 -        [DataMember]
    3.94 -        public int Row { get; set; }
    3.95 +		public Callback(DisplayClient aClient)
    3.96 +        {
    3.97 +            DisplayClient = aClient;
    3.98 +        }
    3.99  
   3.100 -        [DataMember]
   3.101 -        public int ColumnSpan { get; set; }
   3.102 +        public void OnConnected()
   3.103 +        {
   3.104 +            //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
   3.105 +            //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
   3.106  
   3.107 -        [DataMember]
   3.108 -        public int RowSpan { get; set; }
   3.109 +            MessageBox.Show("OnConnected()", "Client");
   3.110 +        }
   3.111  
   3.112 +
   3.113 +        public void OnCloseOrder()
   3.114 +        {
   3.115 +			DisplayClient.Close();
   3.116 +            //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
   3.117 +            //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
   3.118 +
   3.119 +            //MessageBox.Show("OnServerClosing()", "Client");
   3.120 +            //MainForm.CloseConnectionThreadSafe();
   3.121 +            //MainForm.CloseThreadSafe();
   3.122 +        }
   3.123 +
   3.124 +        //From IDisposable
   3.125 +        public void Dispose()
   3.126 +        {
   3.127 +
   3.128 +        }
   3.129      }
   3.130  
   3.131  
   3.132      /// <summary>
   3.133 -    /// TextField can be send to our server to be displayed on the screen.
   3.134 -    /// </summary>
   3.135 -    [DataContract]
   3.136 -    public class TextField : DataField
   3.137 -    {
   3.138 -        public TextField()
   3.139 -        {
   3.140 -            Index = 0;
   3.141 -            Text = "";
   3.142 -            Alignment = ContentAlignment.MiddleLeft;
   3.143 -        }
   3.144 -
   3.145 -        public TextField(int aIndex, string aText = "", ContentAlignment aAlignment = ContentAlignment.MiddleLeft)
   3.146 -        {
   3.147 -            Index = aIndex;
   3.148 -            Text = aText;
   3.149 -            Alignment = aAlignment;
   3.150 -        }
   3.151 -
   3.152 -        [DataMember]
   3.153 -        public int Index { get; set; }
   3.154 -
   3.155 -        [DataMember]
   3.156 -        public string Text { get; set; }
   3.157 -
   3.158 -        [DataMember]
   3.159 -        public ContentAlignment Alignment { get; set; }
   3.160 -    }
   3.161 -
   3.162 -    /// <summary>
   3.163 -    /// Define our SharpDisplay service.
   3.164 -    /// Clients and servers must implement it to communicate with one another.
   3.165 -    /// Through this service clients can send requests to a server.
   3.166 -    /// Through this service a server session can receive requests from a client.
   3.167 -    /// </summary>
   3.168 -    [ServiceContract(CallbackContract = typeof(ICallback), SessionMode = SessionMode.Required)]
   3.169 -    public interface IService
   3.170 -    {
   3.171 -        /// <summary>
   3.172 -        /// Set the name of this client.
   3.173 -        /// Name is a convenient way to recognize your client.
   3.174 -        /// Naming you client is not mandatory.
   3.175 -        /// In the absence of a name the session ID is often used instead.
   3.176 -        /// </summary>
   3.177 -        /// <param name="aClientName"></param>
   3.178 -        [OperationContract(IsOneWay = true)]
   3.179 -        void SetName(string aClientName);
   3.180 -
   3.181 -
   3.182 -        /// <summary>
   3.183 -        /// </summary>
   3.184 -        /// <param name="aLayout"></param>
   3.185 -        [OperationContract(IsOneWay = true)]
   3.186 -        void SetLayout(TableLayout aLayout);
   3.187 -
   3.188 -        /// <summary>
   3.189 -        /// Put the given text in the given field on your display.
   3.190 -        /// Fields are often just lines of text.
   3.191 -        /// </summary>
   3.192 -        /// <param name="aTextFieldIndex"></param>
   3.193 -        [OperationContract(IsOneWay = true)]
   3.194 -        void SetText(TextField aTextField);
   3.195 -
   3.196 -        /// <summary>
   3.197 -        /// Allows a client to set multiple text fields at once.
   3.198 -        /// </summary>
   3.199 -        /// <param name="aTexts"></param>
   3.200 -        [OperationContract(IsOneWay = true)]
   3.201 -        void SetTexts(System.Collections.Generic.IList<TextField> aTextFields);
   3.202 -
   3.203 -        /// <summary>
   3.204 -        /// Provides the number of clients currently connected
   3.205 -        /// </summary>
   3.206 -        /// <returns></returns>
   3.207 -        [OperationContract()]
   3.208 -        int ClientCount();
   3.209 -
   3.210 -    }
   3.211 -
   3.212 -    /// <summary>
   3.213 -    /// SharDisplay callback provides a means for a server to notify its clients.
   3.214 -    /// </summary>
   3.215 -    public interface ICallback
   3.216 -    {
   3.217 -        [OperationContract(IsOneWay = true)]
   3.218 -        void OnConnected();
   3.219 -
   3.220 -        /// <summary>
   3.221 -        /// Tell our client to close its connection.
   3.222 -        /// Notably sent when the server is shutting down.
   3.223 -        /// </summary>
   3.224 -        [OperationContract(IsOneWay = true)]
   3.225 -        void OnCloseOrder();
   3.226 -    }
   3.227 -
   3.228 -
   3.229 -
   3.230 -}
   3.231 -
   3.232 -
   3.233 -
   3.234 -namespace SharpDisplay
   3.235 -{
   3.236 -
   3.237 -    /// <summary>
   3.238      ///
   3.239      /// </summary>
   3.240      [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
   3.241      public class Client : DuplexClientBase<IService>
   3.242      {
   3.243 -        public string Name { get; set; }
   3.244          public string SessionId { get { return InnerChannel.SessionId; } }
   3.245  
   3.246          public Client(ICallback aCallback)
   3.247 @@ -210,7 +67,6 @@
   3.248  
   3.249          public void SetName(string aClientName)
   3.250          {
   3.251 -            Name = aClientName;
   3.252              Channel.SetName(aClientName);
   3.253          }
   3.254  
   3.255 @@ -219,14 +75,14 @@
   3.256              Channel.SetLayout(aLayout);
   3.257          }
   3.258  
   3.259 -        public void SetText(TextField aTextField)
   3.260 +        public void SetField(DataField aField)
   3.261          {
   3.262 -            Channel.SetText(aTextField);
   3.263 +            Channel.SetField(aField);
   3.264          }
   3.265  
   3.266 -        public void SetTexts(System.Collections.Generic.IList<TextField> aTextFields)
   3.267 +        public void SetFields(System.Collections.Generic.IList<DataField> aFields)
   3.268          {
   3.269 -            Channel.SetTexts(aTextFields);
   3.270 +            Channel.SetFields(aFields);
   3.271          }
   3.272  
   3.273          public int ClientCount()
   3.274 @@ -236,10 +92,200 @@
   3.275  
   3.276          public bool IsReady()
   3.277          {
   3.278 -            return State == CommunicationState.Opened;
   3.279 +            return State == CommunicationState.Opened || State == CommunicationState.Created;
   3.280          }
   3.281 +    }
   3.282 +
   3.283 +
   3.284 +    /// <summary>
   3.285 +    /// Handle connection with our Sharp Display Server.
   3.286 +    /// If the connection is faulted it will attempt to restart it.
   3.287 +    /// </summary>
   3.288 +    public class DisplayClient
   3.289 +    {
   3.290 +        private Client iClient;
   3.291 +        private Callback iCallback;
   3.292 +        private bool resetingConnection = false;
   3.293 +
   3.294 +        //private MainForm MainForm { get; set; }
   3.295 +        public string SessionId { get { return iClient.SessionId; } }
   3.296 +        public string Name { get; private set; }
   3.297 +        private TableLayout Layout { get; set; }
   3.298 +        private System.Collections.Generic.IList<DataField> Fields { get; set; }
   3.299 +
   3.300 +
   3.301 +        public DisplayClient(/*MainForm aMainForm*/)
   3.302 +        {
   3.303 +            //MainForm = aMainForm;
   3.304 +            Name = "";
   3.305 +            Fields = new DataField[]{};
   3.306 +        }
   3.307 +
   3.308 +        /// <summary>
   3.309 +        /// Initialize our server connection.
   3.310 +        /// </summary>
   3.311 +        public void Open()
   3.312 +        {
   3.313 +            iCallback = new Callback(this);
   3.314 +            iClient = new Client(iCallback);
   3.315 +        }
   3.316 +
   3.317 +        /// <summary>
   3.318 +        /// Terminate our server connection.
   3.319 +        /// </summary>
   3.320 +        public void Close()
   3.321 +        {
   3.322 +            iClient.Close();
   3.323 +            iClient = null;
   3.324 +            iCallback.Dispose();
   3.325 +            iCallback = null;
   3.326 +        }
   3.327 +
   3.328 +        /// <summary>
   3.329 +        /// Tells whether a server connection is available.
   3.330 +        /// </summary>
   3.331 +        /// <returns>True if a server connection is available. False otherwise.</returns>
   3.332 +        public bool IsReady()
   3.333 +        {
   3.334 +            return (iClient != null && iCallback != null && iClient.IsReady());
   3.335 +        }
   3.336 +
   3.337 +        /// <summary>
   3.338 +        /// Check if our server connection is available and attempt reset it if it isn't.
   3.339 +        /// This is notably dealing with timed out connections.
   3.340 +        /// </summary>
   3.341 +        public void CheckConnection()
   3.342 +        {
   3.343 +            if (!IsReady() && !resetingConnection)
   3.344 +            {
   3.345 +                //Try to reconnect
   3.346 +                Open();
   3.347 +
   3.348 +                //Avoid stack overflow in case of persisting failure
   3.349 +                resetingConnection = true;
   3.350 +
   3.351 +                try
   3.352 +                {
   3.353 +                    //On reconnect there is a bunch of properties we need to reset
   3.354 +                    if (Name != "")
   3.355 +                    {
   3.356 +                        iClient.SetName(Name);
   3.357 +                    }
   3.358 +
   3.359 +                    SetLayout(Layout);
   3.360 +                    iClient.SetFields(Fields);
   3.361 +                }
   3.362 +                finally
   3.363 +                {
   3.364 +                    //Make sure our this state does not get out of sync
   3.365 +                    resetingConnection = true;
   3.366 +                }
   3.367 +            }
   3.368 +        }
   3.369 +
   3.370 +        public void SetName(string aClientName)
   3.371 +        {
   3.372 +            Name = aClientName;
   3.373 +            CheckConnection();
   3.374 +            iClient.SetName(aClientName);
   3.375 +        }
   3.376 +
   3.377 +
   3.378 +        public void SetLayout(TableLayout aLayout)
   3.379 +        {
   3.380 +            Layout = aLayout;
   3.381 +            CheckConnection();
   3.382 +            iClient.SetLayout(aLayout);
   3.383 +        }
   3.384 +
   3.385 +        /// <summary>
   3.386 +        /// Set the specified field.
   3.387 +        /// </summary>
   3.388 +        /// <param name="aField"></param>
   3.389 +        /// <returns>True if the specified field was set client side. False means you need to redefine all your fields using CreateFields.</returns>
   3.390 +        public bool SetField(DataField aField)
   3.391 +        {
   3.392 +            int i = 0;
   3.393 +            bool fieldFound = false;
   3.394 +            foreach (DataField field in Fields)
   3.395 +            {
   3.396 +                if (field.Index == aField.Index)
   3.397 +                {
   3.398 +                    //Update our field then
   3.399 +                    Fields[i] = aField;
   3.400 +                    fieldFound = true;
   3.401 +                    break;
   3.402 +                }
   3.403 +                i++;
   3.404 +            }
   3.405 +
   3.406 +            if (!fieldFound)
   3.407 +            {
   3.408 +                //Field not found, make to use SetFields with all your fields at least once after setting your layout.
   3.409 +                return false;
   3.410 +            }
   3.411 +
   3.412 +            CheckConnection();
   3.413 +            iClient.SetField(aField);
   3.414 +            return true;
   3.415 +        }
   3.416 +
   3.417 +        /// <summary>
   3.418 +        /// Use this function when updating existing fields.
   3.419 +        /// </summary>
   3.420 +        /// <param name="aFields"></param>
   3.421 +        public bool SetFields(System.Collections.Generic.IList<DataField> aFields)
   3.422 +        {
   3.423 +            int fieldFoundCount = 0;
   3.424 +            foreach (DataField fieldUpdate in aFields)
   3.425 +            {
   3.426 +                int i = 0;
   3.427 +                foreach (DataField existingField in Fields)
   3.428 +                {
   3.429 +                    if (existingField.Index == fieldUpdate.Index)
   3.430 +                    {
   3.431 +                        //Update our field then
   3.432 +                        Fields[i] = fieldUpdate;
   3.433 +                        fieldFoundCount++;
   3.434 +                        //Move on to the next field
   3.435 +                        break;
   3.436 +                    }
   3.437 +                    i++;
   3.438 +                }
   3.439 +            }
   3.440 +
   3.441 +            //
   3.442 +            if (fieldFoundCount!=aFields.Count)
   3.443 +            {
   3.444 +                //Field not found, make sure to use SetFields with all your fields at least once after setting your layout.
   3.445 +                return false;
   3.446 +            }
   3.447 +
   3.448 +            CheckConnection();
   3.449 +            iClient.SetFields(aFields);
   3.450 +            return true;
   3.451 +        }
   3.452 +
   3.453 +        /// <summary>
   3.454 +        /// Use this function when creating your fields.
   3.455 +        /// </summary>
   3.456 +        /// <param name="aFields"></param>
   3.457 +        public void CreateFields(System.Collections.Generic.IList<DataField> aFields)
   3.458 +        {
   3.459 +            Fields = aFields;
   3.460 +            CheckConnection();
   3.461 +            iClient.SetFields(aFields);
   3.462 +        }
   3.463 +
   3.464 +        public int ClientCount()
   3.465 +        {
   3.466 +            CheckConnection();
   3.467 +            return iClient.ClientCount();
   3.468 +        }
   3.469 +
   3.470 +
   3.471  
   3.472      }
   3.473  
   3.474  
   3.475 -}
   3.476 \ No newline at end of file
   3.477 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/GUI/SharpDisplayInterface.cs	Thu Jan 01 23:35:49 2015 +0100
     4.3 @@ -0,0 +1,204 @@
     4.4 +//
     4.5 +// Define a public API for both SharpDisplay client and server to use.
     4.6 +//
     4.7 +
     4.8 +using System;
     4.9 +using System.Collections.Generic;
    4.10 +using System.Linq;
    4.11 +using System.Text;
    4.12 +using System.Threading.Tasks;
    4.13 +using System.ServiceModel;
    4.14 +using System.Collections;
    4.15 +using System.Drawing;
    4.16 +using System.Runtime.Serialization;
    4.17 +using System.Windows.Forms;
    4.18 +
    4.19 +
    4.20 +namespace SharpDisplay
    4.21 +{
    4.22 +	/// <summary>
    4.23 +	/// For client to specify a specific layout.
    4.24 +	/// </summary>
    4.25 +	[DataContract]
    4.26 +	public class TableLayout
    4.27 +	{
    4.28 +		public TableLayout()
    4.29 +		{
    4.30 +			Columns = new List<ColumnStyle>();
    4.31 +			Rows = new List<RowStyle>();
    4.32 +			Cells = new List<DataField>();
    4.33 +		}
    4.34 +
    4.35 +		public TableLayout(int aColumnCount, int aRowCount)
    4.36 +		{
    4.37 +			Columns = new List<ColumnStyle>();
    4.38 +			Rows = new List<RowStyle>();
    4.39 +
    4.40 +			for (int i = 0; i < aColumnCount; i++)
    4.41 +			{
    4.42 +				Columns.Add(new ColumnStyle(SizeType.Percent, 100 / aColumnCount));
    4.43 +			}
    4.44 +
    4.45 +			for (int i = 0; i < aRowCount; i++)
    4.46 +			{
    4.47 +				Rows.Add(new RowStyle(SizeType.Percent, 100 / aRowCount));
    4.48 +			}
    4.49 +		}
    4.50 +
    4.51 +		[DataMember]
    4.52 +		public List<DataField> Cells { get; set; }
    4.53 +
    4.54 +		[DataMember]
    4.55 +		public List<ColumnStyle> Columns { get; set; }
    4.56 +
    4.57 +		[DataMember]
    4.58 +		public List<RowStyle> Rows { get; set; }
    4.59 +	}
    4.60 +
    4.61 +	/// <summary>
    4.62 +	///
    4.63 +	/// </summary>
    4.64 +	[DataContract]
    4.65 +	public class DataField
    4.66 +	{
    4.67 +		public DataField()
    4.68 +		{
    4.69 +			Index = 0;
    4.70 +			ColumnSpan = 1;
    4.71 +			RowSpan = 1;
    4.72 +			//Text
    4.73 +			Text = "";
    4.74 +			Alignment = ContentAlignment.MiddleLeft;
    4.75 +			//Bitmap
    4.76 +			Bitmap = null;
    4.77 +		}
    4.78 +
    4.79 +		//Text constructor
    4.80 +		public DataField(int aIndex, string aText = "", ContentAlignment aAlignment = ContentAlignment.MiddleLeft)
    4.81 +		{
    4.82 +			ColumnSpan = 1;
    4.83 +			RowSpan = 1;
    4.84 +			Index = aIndex;
    4.85 +			Text = aText;
    4.86 +			Alignment = aAlignment;
    4.87 +			//
    4.88 +			Bitmap = null;
    4.89 +		}
    4.90 +
    4.91 +		//Bitmap constructor
    4.92 +		public DataField(int aIndex, Bitmap aBitmap)
    4.93 +		{
    4.94 +			ColumnSpan = 1;
    4.95 +			RowSpan = 1;
    4.96 +			Index = aIndex;
    4.97 +			Bitmap = aBitmap;
    4.98 +			//Text
    4.99 +			Text = "";
   4.100 +			Alignment = ContentAlignment.MiddleLeft;
   4.101 +		}
   4.102 +
   4.103 +
   4.104 +		//Generic layout properties
   4.105 +		[DataMember]
   4.106 +		public int Index { get; set; }
   4.107 +
   4.108 +		[DataMember]
   4.109 +		public int Column { get; set; }
   4.110 +
   4.111 +		[DataMember]
   4.112 +		public int Row { get; set; }
   4.113 +
   4.114 +		[DataMember]
   4.115 +		public int ColumnSpan { get; set; }
   4.116 +
   4.117 +		[DataMember]
   4.118 +		public int RowSpan { get; set; }
   4.119 +
   4.120 +		//Text properties
   4.121 +		[DataMember]
   4.122 +		public string Text { get; set; }
   4.123 +
   4.124 +		[DataMember]
   4.125 +		public ContentAlignment Alignment { get; set; }
   4.126 +
   4.127 +		//Bitmap properties
   4.128 +		[DataMember]
   4.129 +		public Bitmap Bitmap { get; set; }
   4.130 +
   4.131 +		//
   4.132 +		public bool IsBitmap { get { return Bitmap != null; } }
   4.133 +		//
   4.134 +		public bool IsText { get { return Bitmap == null; } }
   4.135 +		//
   4.136 +		public bool IsSameLayout(DataField aField)
   4.137 +		{
   4.138 +			return (aField.ColumnSpan == ColumnSpan && aField.RowSpan == RowSpan);
   4.139 +		}
   4.140 +	}
   4.141 +
   4.142 +	/// <summary>
   4.143 +	/// Define our SharpDisplay service.
   4.144 +	/// Clients and servers must implement it to communicate with one another.
   4.145 +	/// Through this service clients can send requests to a server.
   4.146 +	/// Through this service a server session can receive requests from a client.
   4.147 +	/// </summary>
   4.148 +	[ServiceContract(CallbackContract = typeof(ICallback), SessionMode = SessionMode.Required)]
   4.149 +	public interface IService
   4.150 +	{
   4.151 +		/// <summary>
   4.152 +		/// Set the name of this client.
   4.153 +		/// Name is a convenient way to recognize your client.
   4.154 +		/// Naming you client is not mandatory.
   4.155 +		/// In the absence of a name the session ID is often used instead.
   4.156 +		/// </summary>
   4.157 +		/// <param name="aClientName"></param>
   4.158 +		[OperationContract(IsOneWay = true)]
   4.159 +		void SetName(string aClientName);
   4.160 +
   4.161 +		/// <summary>
   4.162 +		/// </summary>
   4.163 +		/// <param name="aLayout"></param>
   4.164 +		[OperationContract(IsOneWay = true)]
   4.165 +		void SetLayout(TableLayout aLayout);
   4.166 +
   4.167 +		/// <summary>
   4.168 +		/// Set the given field on your display.
   4.169 +		/// Fields are often just lines of text or bitmaps.
   4.170 +		/// </summary>
   4.171 +		/// <param name="aTextFieldIndex"></param>
   4.172 +		[OperationContract(IsOneWay = true)]
   4.173 +		void SetField(DataField aField);
   4.174 +
   4.175 +		/// <summary>
   4.176 +		/// Allows a client to set multiple fields at once.
   4.177 +		/// </summary>
   4.178 +		/// <param name="aFields"></param>
   4.179 +		[OperationContract(IsOneWay = true)]
   4.180 +		void SetFields(System.Collections.Generic.IList<DataField> aFields);
   4.181 +
   4.182 +		/// <summary>
   4.183 +		/// Provides the number of clients currently connected
   4.184 +		/// </summary>
   4.185 +		/// <returns></returns>
   4.186 +		[OperationContract()]
   4.187 +		int ClientCount();
   4.188 +
   4.189 +	}
   4.190 +
   4.191 +	/// <summary>
   4.192 +	/// SharDisplay callback provides a means for a server to notify its clients.
   4.193 +	/// </summary>
   4.194 +	public interface ICallback
   4.195 +	{
   4.196 +		[OperationContract(IsOneWay = true)]
   4.197 +		void OnConnected();
   4.198 +
   4.199 +		/// <summary>
   4.200 +		/// Tell our client to close its connection.
   4.201 +		/// Notably sent when the server is shutting down.
   4.202 +		/// </summary>
   4.203 +		[OperationContract(IsOneWay = true)]
   4.204 +		void OnCloseOrder();
   4.205 +	}
   4.206 +
   4.207 +}
     5.1 --- a/OpenHardwareMonitor.csproj	Mon Sep 22 21:59:11 2014 +0200
     5.2 +++ b/OpenHardwareMonitor.csproj	Thu Jan 01 23:35:49 2015 +0100
     5.3 @@ -129,6 +129,7 @@
     5.4      <Compile Include="GUI\SensorSharpDisplay.cs" />
     5.5      <Compile Include="GUI\SharpDisplay.cs" />
     5.6      <Compile Include="GUI\SharpDisplayClient.cs" />
     5.7 +    <Compile Include="GUI\SharpDisplayInterface.cs" />
     5.8      <Compile Include="GUI\ShowDesktop.cs" />
     5.9      <Compile Include="GUI\SoundGraphDisplay.cs" />
    5.10      <Compile Include="GUI\SoundGraphServer.cs" />