Server/MainForm.cs
author sl
Fri, 15 Aug 2014 10:20:01 +0200
changeset 30 c375286d1a1c
parent 29 c4e03315035c
child 31 f19b04646b6a
permissions -rw-r--r--
Still trying to setup WCF for us to work nicely.
Now using multi threading and reliable session.
Implementing thread safe functions where needed.
Enforcing session mode.
Fixing bug in marquee label as we forgot to reset current position when text is changed.
     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Data;
     5 using System.Drawing;
     6 using System.Linq;
     7 using System.Text;
     8 using System.Threading.Tasks;
     9 using System.Windows.Forms;
    10 using System.IO;
    11 using CodeProject.Dialog;
    12 using System.Drawing.Imaging;
    13 using System.ServiceModel;
    14 using System.Threading;
    15 //
    16 using SharpDisplayInterface;
    17 using SharpDisplayClient;
    18 
    19 
    20 namespace SharpDisplayManager
    21 {
    22     public partial class MainForm : Form
    23     {
    24         DateTime LastTickTime;
    25         Display iDisplay;
    26         System.Drawing.Bitmap iBmp;
    27         bool iCreateBitmap; //Workaround render to bitmap issues when minimized
    28         ServiceHost iServiceHost;
    29         /// <summary>
    30         /// Our collection of clients
    31         /// </summary>
    32         public Dictionary<string, IDisplayServiceCallback> iClients;
    33         public bool iClosing;
    34 
    35         public MainForm()
    36         {
    37             LastTickTime = DateTime.Now;
    38             iDisplay = new Display();
    39             iClients = new Dictionary<string, IDisplayServiceCallback>();
    40 
    41             InitializeComponent();
    42             UpdateStatus();
    43 
    44             //Load settings
    45             marqueeLabelTop.Font = Properties.Settings.Default.DisplayFont;
    46             marqueeLabelBottom.Font = Properties.Settings.Default.DisplayFont;
    47             checkBoxShowBorders.Checked = Properties.Settings.Default.DisplayShowBorders;
    48             checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
    49             checkBoxReverseScreen.Checked = Properties.Settings.Default.DisplayReverseScreen;
    50             //
    51             tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
    52             //We have a bug when drawing minimized and reusing our bitmap
    53             iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
    54             iCreateBitmap = false;
    55         }
    56 
    57         private void MainForm_Load(object sender, EventArgs e)
    58         {
    59             StartServer();
    60 
    61             if (Properties.Settings.Default.DisplayConnectOnStartup)
    62             {
    63                 iDisplay.Open();
    64                 UpdateStatus();
    65             }
    66         }
    67 
    68 
    69         private void buttonFont_Click(object sender, EventArgs e)
    70         {
    71             //fontDialog.ShowColor = true;
    72             //fontDialog.ShowApply = true;
    73             fontDialog.ShowEffects = true;
    74             fontDialog.Font = marqueeLabelTop.Font;
    75 
    76             fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
    77 
    78             //fontDialog.ShowHelp = true;
    79 
    80             //fontDlg.MaxSize = 40;
    81             //fontDlg.MinSize = 22;
    82 
    83             //fontDialog.Parent = this;
    84             //fontDialog.StartPosition = FormStartPosition.CenterParent;
    85 
    86             //DlgBox.ShowDialog(fontDialog);
    87 
    88             //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
    89             if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
    90             {
    91 
    92                 //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
    93 
    94                 //MessageBox.Show("Ok");
    95                 marqueeLabelTop.Font = fontDialog.Font;
    96                 marqueeLabelBottom.Font = fontDialog.Font;
    97                 Properties.Settings.Default.DisplayFont = fontDialog.Font;
    98                 Properties.Settings.Default.Save();
    99                 //label1.Font = fontDlg.Font;
   100                 //textBox1.BackColor = fontDlg.Color;
   101                 //label1.ForeColor = fontDlg.Color;
   102             }
   103         }
   104 
   105         private void buttonCapture_Click(object sender, EventArgs e)
   106         {
   107             System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
   108             tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
   109             //Bitmap bmpToSave = new Bitmap(bmp);
   110             bmp.Save("D:\\capture.png");
   111 
   112             marqueeLabelTop.Text = "Sweet";
   113 
   114             /*
   115             string outputFileName = "d:\\capture.png";
   116             using (MemoryStream memory = new MemoryStream())
   117             {
   118                 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
   119                 {
   120                     bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
   121                     byte[] bytes = memory.ToArray();
   122                     fs.Write(bytes, 0, bytes.Length);
   123                 }
   124             }
   125              */
   126 
   127         }
   128 
   129         private void CheckForRequestResults()
   130         {
   131             if (iDisplay.IsRequestPending())
   132             {
   133                 switch (iDisplay.AttemptRequestCompletion())
   134                 {
   135                     case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
   136                         if (iDisplay.PowerSupplyStatus())
   137                         {
   138                             toolStripStatusLabelPower.Text = "ON";
   139                         }
   140                         else
   141                         {
   142                             toolStripStatusLabelPower.Text = "OFF";
   143                         }
   144                         //Issue next request then
   145                         iDisplay.RequestDeviceId();
   146                         break;
   147 
   148                     case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
   149                         toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
   150                         //Issue next request then
   151                         iDisplay.RequestFirmwareRevision();
   152                         break;
   153 
   154                     case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
   155                         toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
   156                         //No more request to issue
   157                         break;
   158                 }
   159             }
   160         }
   161 
   162 
   163         public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
   164 
   165 
   166         public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
   167         {
   168             return aBmp.Width - aX - 1;
   169         }
   170 
   171         public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
   172         {
   173             return iBmp.Height - aY - 1;
   174         }
   175 
   176         public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
   177         {
   178             return aX;
   179         }
   180 
   181         public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
   182         {
   183             return aY;
   184         }
   185 
   186 
   187         //This is our timer tick responsible to perform our render
   188         private void timer_Tick(object sender, EventArgs e)
   189         {
   190             //Update our animations
   191             DateTime NewTickTime = DateTime.Now;
   192 
   193             marqueeLabelTop.UpdateAnimation(LastTickTime, NewTickTime);
   194             marqueeLabelBottom.UpdateAnimation(LastTickTime, NewTickTime);
   195 
   196             //Update our display
   197             if (iDisplay.IsOpen())
   198             {
   199                 CheckForRequestResults();
   200 
   201                 //Draw to bitmap
   202                 if (iCreateBitmap)
   203                 {
   204                     iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   205                 }
   206                 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
   207                 //iBmp.Save("D:\\capture.png");
   208 
   209                 //Select proper coordinate translation functions
   210                 //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
   211                 CoordinateTranslationDelegate screenX;
   212                 CoordinateTranslationDelegate screenY;
   213 
   214                 if (Properties.Settings.Default.DisplayReverseScreen)
   215                 {
   216                     screenX = ScreenReversedX;
   217                     screenY = ScreenReversedY;
   218                 }
   219                 else
   220                 {
   221                     screenX = ScreenX;
   222                     screenY = ScreenY;
   223                 }
   224 
   225                 //Send it to our display
   226                 for (int i = 0; i < iBmp.Width; i++)
   227                 {
   228                     for (int j = 0; j < iBmp.Height; j++)
   229                     {
   230                         unchecked
   231                         {
   232                             uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
   233                             //For some reason when the app is minimized in the task bar only the alpha of our color is set.
   234                             //Thus that strange test for rendering to work both when the app is in the task bar and when it isn't.
   235                             iDisplay.SetPixel(screenX(iBmp, i), screenY(iBmp, j), Convert.ToInt32(!(color != 0xFF000000)));
   236                         }
   237                     }
   238                 }
   239 
   240                 iDisplay.SwapBuffers();
   241 
   242             }
   243 
   244             //Compute instant FPS
   245             toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " FPS";
   246 
   247             LastTickTime = NewTickTime;
   248 
   249         }
   250 
   251         private void buttonOpen_Click(object sender, EventArgs e)
   252         {
   253             if (iDisplay.Open())
   254             {
   255                 UpdateStatus();
   256                 iDisplay.RequestPowerSupplyStatus();
   257             }
   258             else
   259             {
   260                 UpdateStatus();
   261                 toolStripStatusLabelConnect.Text = "Connection error";
   262             }
   263 
   264         }
   265 
   266         private void buttonClose_Click(object sender, EventArgs e)
   267         {
   268             iDisplay.Close();
   269             UpdateStatus();
   270         }
   271 
   272         private void buttonClear_Click(object sender, EventArgs e)
   273         {
   274             iDisplay.Clear();
   275             iDisplay.SwapBuffers();
   276         }
   277 
   278         private void buttonFill_Click(object sender, EventArgs e)
   279         {
   280             iDisplay.Fill();
   281             iDisplay.SwapBuffers();
   282         }
   283 
   284         private void trackBarBrightness_Scroll(object sender, EventArgs e)
   285         {
   286             Properties.Settings.Default.DisplayBrightness = trackBarBrightness.Value;
   287             Properties.Settings.Default.Save();
   288             iDisplay.SetBrightness(trackBarBrightness.Value);
   289 
   290         }
   291 
   292         private void UpdateStatus()
   293         {
   294             if (iDisplay.IsOpen())
   295             {
   296                 buttonFill.Enabled = true;
   297                 buttonClear.Enabled = true;
   298                 buttonOpen.Enabled = false;
   299                 buttonClose.Enabled = true;
   300                 trackBarBrightness.Enabled = true;
   301                 trackBarBrightness.Minimum = iDisplay.MinBrightness();
   302                 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
   303                 trackBarBrightness.Value = Properties.Settings.Default.DisplayBrightness;
   304                 trackBarBrightness.LargeChange = Math.Max(1,(iDisplay.MaxBrightness() - iDisplay.MinBrightness())/5);
   305                 trackBarBrightness.SmallChange = 1;
   306                 iDisplay.SetBrightness(Properties.Settings.Default.DisplayBrightness);
   307 
   308                 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
   309                 //+ " - " + iDisplay.SerialNumber();
   310             }
   311             else
   312             {
   313                 buttonFill.Enabled = false;
   314                 buttonClear.Enabled = false;
   315                 buttonOpen.Enabled = true;
   316                 buttonClose.Enabled = false;
   317                 trackBarBrightness.Enabled = false;
   318                 toolStripStatusLabelConnect.Text = "Disconnected";
   319             }
   320         }
   321 
   322 
   323 
   324         private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
   325         {
   326             //Save our show borders setting
   327             tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
   328             Properties.Settings.Default.DisplayShowBorders = checkBoxShowBorders.Checked;
   329             Properties.Settings.Default.Save();
   330         }
   331 
   332         private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
   333         {
   334             //Save our connect on startup setting
   335             Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
   336             Properties.Settings.Default.Save();
   337         }
   338 
   339         private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
   340         {
   341             //Save our reverse screen setting
   342             Properties.Settings.Default.DisplayReverseScreen = checkBoxReverseScreen.Checked;
   343             Properties.Settings.Default.Save();
   344         }
   345 
   346         private void MainForm_Resize(object sender, EventArgs e)
   347         {
   348             if (WindowState == FormWindowState.Minimized)
   349             {
   350                 // Do some stuff
   351                 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   352                 iCreateBitmap = true;
   353             }
   354         }
   355 
   356         private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
   357         {
   358             StopServer();
   359         }
   360 
   361         public void StartServer()
   362         {
   363             iServiceHost = new ServiceHost
   364                 (
   365                     typeof(DisplayServer),
   366                     new Uri[] { new Uri("net.tcp://localhost:8001/") }
   367                 );
   368 
   369             iServiceHost.AddServiceEndpoint(typeof(IDisplayService), new NetTcpBinding(SecurityMode.None,true), "DisplayService");
   370             iServiceHost.Open();
   371         }
   372 
   373         public void StopServer()
   374         {
   375             //Tell connected client first? Is that possible?
   376 
   377             if (iClients.Count>0)
   378             {
   379                 //Tell our clients
   380                 BroadcastCloseEvent();
   381             }
   382 
   383             //iServiceHost.Close();
   384 
   385         }
   386 
   387         public void BroadcastCloseEvent()
   388         {
   389             var inactiveClients = new List<string>();
   390             foreach (var client in iClients)
   391             {
   392                 //if (client.Key != eventData.ClientName)
   393                 {
   394                     try
   395                     {
   396                         client.Value.OnServerClosing(/*eventData*/);
   397                     }
   398                     catch (Exception ex)
   399                     {
   400                         inactiveClients.Add(client.Key);
   401                     }
   402                 }
   403             }
   404 
   405             if (inactiveClients.Count > 0)
   406             {
   407                 foreach (var client in inactiveClients)
   408                 {
   409                     iClients.Remove(client);
   410                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
   411                 }
   412             }
   413         }
   414 
   415         private void buttonStartClient_Click(object sender, EventArgs e)
   416         {
   417             Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
   418             clientThread.Start();
   419         }
   420 
   421         private void buttonSuspend_Click(object sender, EventArgs e)
   422         {
   423             timer.Enabled = !timer.Enabled;
   424             if (!timer.Enabled)
   425             {
   426                 buttonSuspend.Text = "Suspend";
   427             }
   428             else
   429             {
   430                 buttonSuspend.Text = "Pause";
   431             }
   432         }
   433 
   434         private void buttonCloseClients_Click(object sender, EventArgs e)
   435         {
   436             BroadcastCloseEvent();
   437         }
   438 
   439         private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
   440         {
   441 
   442         }
   443 
   444         public delegate void AddClientDelegate(string aSessionId, IDisplayServiceCallback aCallback);
   445         public delegate void RemoveClientDelegate(string aSessionId);
   446         public delegate void SetTextDelegate(int aLineIndex, string aText);
   447         public delegate void SetTextsDelegate(System.Collections.Generic.IList<string> aTexts);
   448 
   449        
   450         /// <summary>
   451         /// 
   452         /// </summary>
   453         /// <param name="aSessionId"></param>
   454         /// <param name="aCallback"></param>
   455         public void AddClientThreadSafe(string aSessionId, IDisplayServiceCallback aCallback)
   456         {
   457             if (this.treeViewClients.InvokeRequired)
   458             {
   459                 //Not in the proper thread, invoke ourselves
   460                 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
   461                 this.Invoke(d, new object[] { aSessionId, aCallback });
   462             }
   463             else
   464             {
   465                 //We are in the proper thread
   466                 //Add this session to our collection of clients
   467                 Program.iMainForm.iClients.Add(aSessionId, aCallback);
   468                 //Add this session to our UI
   469                 Program.iMainForm.treeViewClients.Nodes.Add(aSessionId, aSessionId);
   470             }
   471         }
   472 
   473         /// <summary>
   474         /// 
   475         /// </summary>
   476         /// <param name="aSessionId"></param>
   477         public void RemoveClientThreadSafe(string aSessionId)
   478         {
   479             if (this.treeViewClients.InvokeRequired)
   480             {
   481                 //Not in the proper thread, invoke ourselves
   482                 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
   483                 this.Invoke(d, new object[] { aSessionId });
   484             }
   485             else
   486             {
   487                 //We are in the proper thread
   488                             //Remove this session from both client collection and UI tree view
   489                 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
   490                 {
   491                     Program.iMainForm.iClients.Remove(aSessionId);
   492                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
   493                 }                
   494             }
   495         }
   496 
   497         /// <summary>
   498         /// 
   499         /// </summary>
   500         /// <param name="aLineIndex"></param>
   501         /// <param name="aText"></param>
   502         public void SetTextThreadSafe(int aLineIndex, string aText)
   503         {
   504             if (this.treeViewClients.InvokeRequired)
   505             {
   506                 //Not in the proper thread, invoke ourselves
   507                 SetTextDelegate d = new SetTextDelegate(SetTextThreadSafe);
   508                 this.Invoke(d, new object[] { aLineIndex, aText });
   509             }
   510             else
   511             {
   512                 //We are in the proper thread
   513                 //Only support two lines for now
   514                 if (aLineIndex == 0)
   515                 {
   516                     Program.iMainForm.marqueeLabelTop.Text = aText;
   517                 }
   518                 else if (aLineIndex == 1)
   519                 {
   520                     Program.iMainForm.marqueeLabelBottom.Text = aText;
   521                 }
   522             }
   523         }
   524 
   525         /// <summary>
   526         /// 
   527         /// </summary>
   528         /// <param name="aTexts"></param>
   529         public void SetTextsThreadSafe(System.Collections.Generic.IList<string> aTexts)
   530         {
   531             if (this.treeViewClients.InvokeRequired)
   532             {
   533                 //Not in the proper thread, invoke ourselves
   534                 SetTextsDelegate d = new SetTextsDelegate(SetTextsThreadSafe);
   535                 this.Invoke(d, new object[] { aTexts });
   536             }
   537             else
   538             {
   539                 //We are in the proper thread
   540                 //Only support two lines for now
   541                 for (int i = 0; i < aTexts.Count; i++)
   542                 {
   543                     if (i == 0)
   544                     {
   545                         Program.iMainForm.marqueeLabelTop.Text = aTexts[i];
   546                     }
   547                     else if (i == 1)
   548                     {
   549                         Program.iMainForm.marqueeLabelBottom.Text = aTexts[i];
   550                     }
   551                 }
   552             }
   553 
   554         }
   555 
   556     }
   557 }