1.1 --- a/GUI/SharpDisplayClient.cs Mon Sep 22 21:59:11 2014 +0200
1.2 +++ b/GUI/SharpDisplayClient.cs Thu Jan 01 23:35:49 2015 +0100
1.3 @@ -1,207 +1,64 @@
1.4 -/*
1.5 -
1.6 - This Source Code Form is subject to the terms of the Mozilla Public
1.7 - License, v. 2.0. If a copy of the MPL was not distributed with this
1.8 - file, You can obtain one at http://mozilla.org/MPL/2.0/.
1.9 -
1.10 - Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
1.11 -
1.12 -*/
1.13 -
1.14 +
1.15 using System;
1.16 using System.Collections.Generic;
1.17 -using System.Drawing;
1.18 +using System.Linq;
1.19 using System.Text;
1.20 -using System.Diagnostics;
1.21 +using System.Threading.Tasks;
1.22 using System.Windows.Forms;
1.23 -using System.Windows;
1.24 -using OpenHardwareMonitor.Hardware;
1.25 -using OpenHardwareMonitor.Utilities;
1.26 -using System.Runtime.InteropServices;
1.27 -using UacHelpers;
1.28 -//
1.29 +using SharpDisplay;
1.30 using System.ServiceModel;
1.31 -using System.Runtime.Serialization;
1.32 -using SharpDisplay;
1.33 +using System.ServiceModel.Channels;
1.34 +
1.35
1.36 namespace SharpDisplay
1.37 {
1.38 -
1.39 -
1.40 -
1.41 - /// <summary>
1.42 - /// For client to specify a specific layout.
1.43 - /// </summary>
1.44 - [DataContract]
1.45 - public class TableLayout
1.46 - {
1.47 - public TableLayout()
1.48 - {
1.49 - Columns = new List<ColumnStyle>();
1.50 - Rows = new List<RowStyle>();
1.51 - Cells = new List<DataField>();
1.52 - }
1.53 -
1.54 - public TableLayout(int aColumnCount, int aRowCount)
1.55 - {
1.56 - Columns = new List<ColumnStyle>();
1.57 - Rows = new List<RowStyle>();
1.58 -
1.59 - for (int i = 0; i < aColumnCount; i++)
1.60 - {
1.61 - Columns.Add(new ColumnStyle(SizeType.Percent, 100 / aColumnCount));
1.62 - }
1.63 -
1.64 - for (int i = 0; i < aRowCount; i++)
1.65 - {
1.66 - Rows.Add(new RowStyle(SizeType.Percent, 100 / aRowCount));
1.67 - }
1.68 - }
1.69 -
1.70 - [DataMember]
1.71 - public List<DataField> Cells { get; set; }
1.72 -
1.73 - [DataMember]
1.74 - public List<ColumnStyle> Columns { get; set; }
1.75 -
1.76 - [DataMember]
1.77 - public List<RowStyle> Rows { get; set; }
1.78 -
1.79 - }
1.80 -
1.81 /// <summary>
1.82 ///
1.83 /// </summary>
1.84 - [DataContract]
1.85 - public class DataField
1.86 + [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
1.87 + public class Callback : ICallback, IDisposable
1.88 {
1.89 - [DataMember]
1.90 - public int Column { get; set; }
1.91 + private DisplayClient DisplayClient { get; set; }
1.92
1.93 - [DataMember]
1.94 - public int Row { get; set; }
1.95 + public Callback(DisplayClient aClient)
1.96 + {
1.97 + DisplayClient = aClient;
1.98 + }
1.99
1.100 - [DataMember]
1.101 - public int ColumnSpan { get; set; }
1.102 + public void OnConnected()
1.103 + {
1.104 + //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
1.105 + //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
1.106
1.107 - [DataMember]
1.108 - public int RowSpan { get; set; }
1.109 + MessageBox.Show("OnConnected()", "Client");
1.110 + }
1.111
1.112 +
1.113 + public void OnCloseOrder()
1.114 + {
1.115 + DisplayClient.Close();
1.116 + //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
1.117 + //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
1.118 +
1.119 + //MessageBox.Show("OnServerClosing()", "Client");
1.120 + //MainForm.CloseConnectionThreadSafe();
1.121 + //MainForm.CloseThreadSafe();
1.122 + }
1.123 +
1.124 + //From IDisposable
1.125 + public void Dispose()
1.126 + {
1.127 +
1.128 + }
1.129 }
1.130
1.131
1.132 /// <summary>
1.133 - /// TextField can be send to our server to be displayed on the screen.
1.134 - /// </summary>
1.135 - [DataContract]
1.136 - public class TextField : DataField
1.137 - {
1.138 - public TextField()
1.139 - {
1.140 - Index = 0;
1.141 - Text = "";
1.142 - Alignment = ContentAlignment.MiddleLeft;
1.143 - }
1.144 -
1.145 - public TextField(int aIndex, string aText = "", ContentAlignment aAlignment = ContentAlignment.MiddleLeft)
1.146 - {
1.147 - Index = aIndex;
1.148 - Text = aText;
1.149 - Alignment = aAlignment;
1.150 - }
1.151 -
1.152 - [DataMember]
1.153 - public int Index { get; set; }
1.154 -
1.155 - [DataMember]
1.156 - public string Text { get; set; }
1.157 -
1.158 - [DataMember]
1.159 - public ContentAlignment Alignment { get; set; }
1.160 - }
1.161 -
1.162 - /// <summary>
1.163 - /// Define our SharpDisplay service.
1.164 - /// Clients and servers must implement it to communicate with one another.
1.165 - /// Through this service clients can send requests to a server.
1.166 - /// Through this service a server session can receive requests from a client.
1.167 - /// </summary>
1.168 - [ServiceContract(CallbackContract = typeof(ICallback), SessionMode = SessionMode.Required)]
1.169 - public interface IService
1.170 - {
1.171 - /// <summary>
1.172 - /// Set the name of this client.
1.173 - /// Name is a convenient way to recognize your client.
1.174 - /// Naming you client is not mandatory.
1.175 - /// In the absence of a name the session ID is often used instead.
1.176 - /// </summary>
1.177 - /// <param name="aClientName"></param>
1.178 - [OperationContract(IsOneWay = true)]
1.179 - void SetName(string aClientName);
1.180 -
1.181 -
1.182 - /// <summary>
1.183 - /// </summary>
1.184 - /// <param name="aLayout"></param>
1.185 - [OperationContract(IsOneWay = true)]
1.186 - void SetLayout(TableLayout aLayout);
1.187 -
1.188 - /// <summary>
1.189 - /// Put the given text in the given field on your display.
1.190 - /// Fields are often just lines of text.
1.191 - /// </summary>
1.192 - /// <param name="aTextFieldIndex"></param>
1.193 - [OperationContract(IsOneWay = true)]
1.194 - void SetText(TextField aTextField);
1.195 -
1.196 - /// <summary>
1.197 - /// Allows a client to set multiple text fields at once.
1.198 - /// </summary>
1.199 - /// <param name="aTexts"></param>
1.200 - [OperationContract(IsOneWay = true)]
1.201 - void SetTexts(System.Collections.Generic.IList<TextField> aTextFields);
1.202 -
1.203 - /// <summary>
1.204 - /// Provides the number of clients currently connected
1.205 - /// </summary>
1.206 - /// <returns></returns>
1.207 - [OperationContract()]
1.208 - int ClientCount();
1.209 -
1.210 - }
1.211 -
1.212 - /// <summary>
1.213 - /// SharDisplay callback provides a means for a server to notify its clients.
1.214 - /// </summary>
1.215 - public interface ICallback
1.216 - {
1.217 - [OperationContract(IsOneWay = true)]
1.218 - void OnConnected();
1.219 -
1.220 - /// <summary>
1.221 - /// Tell our client to close its connection.
1.222 - /// Notably sent when the server is shutting down.
1.223 - /// </summary>
1.224 - [OperationContract(IsOneWay = true)]
1.225 - void OnCloseOrder();
1.226 - }
1.227 -
1.228 -
1.229 -
1.230 -}
1.231 -
1.232 -
1.233 -
1.234 -namespace SharpDisplay
1.235 -{
1.236 -
1.237 - /// <summary>
1.238 ///
1.239 /// </summary>
1.240 [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
1.241 public class Client : DuplexClientBase<IService>
1.242 {
1.243 - public string Name { get; set; }
1.244 public string SessionId { get { return InnerChannel.SessionId; } }
1.245
1.246 public Client(ICallback aCallback)
1.247 @@ -210,7 +67,6 @@
1.248
1.249 public void SetName(string aClientName)
1.250 {
1.251 - Name = aClientName;
1.252 Channel.SetName(aClientName);
1.253 }
1.254
1.255 @@ -219,14 +75,14 @@
1.256 Channel.SetLayout(aLayout);
1.257 }
1.258
1.259 - public void SetText(TextField aTextField)
1.260 + public void SetField(DataField aField)
1.261 {
1.262 - Channel.SetText(aTextField);
1.263 + Channel.SetField(aField);
1.264 }
1.265
1.266 - public void SetTexts(System.Collections.Generic.IList<TextField> aTextFields)
1.267 + public void SetFields(System.Collections.Generic.IList<DataField> aFields)
1.268 {
1.269 - Channel.SetTexts(aTextFields);
1.270 + Channel.SetFields(aFields);
1.271 }
1.272
1.273 public int ClientCount()
1.274 @@ -236,10 +92,200 @@
1.275
1.276 public bool IsReady()
1.277 {
1.278 - return State == CommunicationState.Opened;
1.279 + return State == CommunicationState.Opened || State == CommunicationState.Created;
1.280 }
1.281 + }
1.282 +
1.283 +
1.284 + /// <summary>
1.285 + /// Handle connection with our Sharp Display Server.
1.286 + /// If the connection is faulted it will attempt to restart it.
1.287 + /// </summary>
1.288 + public class DisplayClient
1.289 + {
1.290 + private Client iClient;
1.291 + private Callback iCallback;
1.292 + private bool resetingConnection = false;
1.293 +
1.294 + //private MainForm MainForm { get; set; }
1.295 + public string SessionId { get { return iClient.SessionId; } }
1.296 + public string Name { get; private set; }
1.297 + private TableLayout Layout { get; set; }
1.298 + private System.Collections.Generic.IList<DataField> Fields { get; set; }
1.299 +
1.300 +
1.301 + public DisplayClient(/*MainForm aMainForm*/)
1.302 + {
1.303 + //MainForm = aMainForm;
1.304 + Name = "";
1.305 + Fields = new DataField[]{};
1.306 + }
1.307 +
1.308 + /// <summary>
1.309 + /// Initialize our server connection.
1.310 + /// </summary>
1.311 + public void Open()
1.312 + {
1.313 + iCallback = new Callback(this);
1.314 + iClient = new Client(iCallback);
1.315 + }
1.316 +
1.317 + /// <summary>
1.318 + /// Terminate our server connection.
1.319 + /// </summary>
1.320 + public void Close()
1.321 + {
1.322 + iClient.Close();
1.323 + iClient = null;
1.324 + iCallback.Dispose();
1.325 + iCallback = null;
1.326 + }
1.327 +
1.328 + /// <summary>
1.329 + /// Tells whether a server connection is available.
1.330 + /// </summary>
1.331 + /// <returns>True if a server connection is available. False otherwise.</returns>
1.332 + public bool IsReady()
1.333 + {
1.334 + return (iClient != null && iCallback != null && iClient.IsReady());
1.335 + }
1.336 +
1.337 + /// <summary>
1.338 + /// Check if our server connection is available and attempt reset it if it isn't.
1.339 + /// This is notably dealing with timed out connections.
1.340 + /// </summary>
1.341 + public void CheckConnection()
1.342 + {
1.343 + if (!IsReady() && !resetingConnection)
1.344 + {
1.345 + //Try to reconnect
1.346 + Open();
1.347 +
1.348 + //Avoid stack overflow in case of persisting failure
1.349 + resetingConnection = true;
1.350 +
1.351 + try
1.352 + {
1.353 + //On reconnect there is a bunch of properties we need to reset
1.354 + if (Name != "")
1.355 + {
1.356 + iClient.SetName(Name);
1.357 + }
1.358 +
1.359 + SetLayout(Layout);
1.360 + iClient.SetFields(Fields);
1.361 + }
1.362 + finally
1.363 + {
1.364 + //Make sure our this state does not get out of sync
1.365 + resetingConnection = true;
1.366 + }
1.367 + }
1.368 + }
1.369 +
1.370 + public void SetName(string aClientName)
1.371 + {
1.372 + Name = aClientName;
1.373 + CheckConnection();
1.374 + iClient.SetName(aClientName);
1.375 + }
1.376 +
1.377 +
1.378 + public void SetLayout(TableLayout aLayout)
1.379 + {
1.380 + Layout = aLayout;
1.381 + CheckConnection();
1.382 + iClient.SetLayout(aLayout);
1.383 + }
1.384 +
1.385 + /// <summary>
1.386 + /// Set the specified field.
1.387 + /// </summary>
1.388 + /// <param name="aField"></param>
1.389 + /// <returns>True if the specified field was set client side. False means you need to redefine all your fields using CreateFields.</returns>
1.390 + public bool SetField(DataField aField)
1.391 + {
1.392 + int i = 0;
1.393 + bool fieldFound = false;
1.394 + foreach (DataField field in Fields)
1.395 + {
1.396 + if (field.Index == aField.Index)
1.397 + {
1.398 + //Update our field then
1.399 + Fields[i] = aField;
1.400 + fieldFound = true;
1.401 + break;
1.402 + }
1.403 + i++;
1.404 + }
1.405 +
1.406 + if (!fieldFound)
1.407 + {
1.408 + //Field not found, make to use SetFields with all your fields at least once after setting your layout.
1.409 + return false;
1.410 + }
1.411 +
1.412 + CheckConnection();
1.413 + iClient.SetField(aField);
1.414 + return true;
1.415 + }
1.416 +
1.417 + /// <summary>
1.418 + /// Use this function when updating existing fields.
1.419 + /// </summary>
1.420 + /// <param name="aFields"></param>
1.421 + public bool SetFields(System.Collections.Generic.IList<DataField> aFields)
1.422 + {
1.423 + int fieldFoundCount = 0;
1.424 + foreach (DataField fieldUpdate in aFields)
1.425 + {
1.426 + int i = 0;
1.427 + foreach (DataField existingField in Fields)
1.428 + {
1.429 + if (existingField.Index == fieldUpdate.Index)
1.430 + {
1.431 + //Update our field then
1.432 + Fields[i] = fieldUpdate;
1.433 + fieldFoundCount++;
1.434 + //Move on to the next field
1.435 + break;
1.436 + }
1.437 + i++;
1.438 + }
1.439 + }
1.440 +
1.441 + //
1.442 + if (fieldFoundCount!=aFields.Count)
1.443 + {
1.444 + //Field not found, make sure to use SetFields with all your fields at least once after setting your layout.
1.445 + return false;
1.446 + }
1.447 +
1.448 + CheckConnection();
1.449 + iClient.SetFields(aFields);
1.450 + return true;
1.451 + }
1.452 +
1.453 + /// <summary>
1.454 + /// Use this function when creating your fields.
1.455 + /// </summary>
1.456 + /// <param name="aFields"></param>
1.457 + public void CreateFields(System.Collections.Generic.IList<DataField> aFields)
1.458 + {
1.459 + Fields = aFields;
1.460 + CheckConnection();
1.461 + iClient.SetFields(aFields);
1.462 + }
1.463 +
1.464 + public int ClientCount()
1.465 + {
1.466 + CheckConnection();
1.467 + return iClient.ClientCount();
1.468 + }
1.469 +
1.470 +
1.471
1.472 }
1.473
1.474
1.475 -}
1.476 \ No newline at end of file
1.477 +}