GUI/MainForm.cs
author moel.mich
Thu, 27 Jan 2011 22:29:43 +0000
changeset 251 49c38a2958c8
parent 247 6dc755f1970e
child 252 e62afa69214f
permissions -rw-r--r--
Added support for AMD family 11h CPUs.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     5   The contents of this file are subject to the Mozilla Public License Version
     6   1.1 (the "License"); you may not use this file except in compliance with
     7   the License. You may obtain a copy of the License at
     8  
     9   http://www.mozilla.org/MPL/
    10 
    11   Software distributed under the License is distributed on an "AS IS" basis,
    12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    13   for the specific language governing rights and limitations under the License.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    17   The Initial Developer of the Original Code is 
    18   Michael Möller <m.moeller@gmx.ch>.
    19   Portions created by the Initial Developer are Copyright (C) 2009-2010
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s): Paul Werelds
    23 
    24   Alternatively, the contents of this file may be used under the terms of
    25   either the GNU General Public License Version 2 or later (the "GPL"), or
    26   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    27   in which case the provisions of the GPL or the LGPL are applicable instead
    28   of those above. If you wish to allow use of your version of this file only
    29   under the terms of either the GPL or the LGPL, and not to allow others to
    30   use your version of this file under the terms of the MPL, indicate your
    31   decision by deleting the provisions above and replace them with the notice
    32   and other provisions required by the GPL or the LGPL. If you do not delete
    33   the provisions above, a recipient may use your version of this file under
    34   the terms of any one of the MPL, the GPL or the LGPL.
    35  
    36 */
    37 
    38 using System;
    39 using System.Collections.Generic;
    40 using System.ComponentModel;
    41 using System.Drawing;
    42 using System.IO;
    43 using System.Windows.Forms;
    44 using Aga.Controls.Tree;
    45 using Aga.Controls.Tree.NodeControls;
    46 using OpenHardwareMonitor.Hardware;
    47 using OpenHardwareMonitor.WMI;
    48 
    49 namespace OpenHardwareMonitor.GUI {
    50   public partial class MainForm : Form {
    51 
    52     private PersistentSettings settings;
    53     private UnitManager unitManager;
    54     private Computer computer;
    55     private Node root;
    56     private TreeModel treeModel;
    57     private IDictionary<ISensor, Color> sensorPlotColors = 
    58       new Dictionary<ISensor, Color>();
    59     private Color[] plotColorPalette;
    60     private SystemTray systemTray;    
    61     private StartupManager startupManager = new StartupManager();
    62     private UpdateVisitor updateVisitor = new UpdateVisitor();
    63     private SensorGadget gadget;
    64 
    65     private UserOption showHiddenSensors;
    66     private UserOption showPlot;
    67     private UserOption showValue;
    68     private UserOption showMin;
    69     private UserOption showMax;
    70     private UserOption startMinimized;
    71     private UserOption minimizeToTray;
    72     private UserOption minimizeOnClose;
    73     private UserOption autoStart;
    74     private UserOption readHddSensors;
    75     private UserOption showGadget;
    76 
    77     private WmiProvider wmiProvider;
    78 
    79     public MainForm() {      
    80       InitializeComponent();
    81 
    82       this.settings = new PersistentSettings();      
    83       this.settings.Load(Path.ChangeExtension(
    84         Application.ExecutablePath, ".config"));
    85 
    86       this.unitManager = new UnitManager(settings);
    87 
    88       // set the DockStyle here, to avoid conflicts with the MainMenu
    89       this.splitContainer.Dock = DockStyle.Fill;
    90             
    91       this.Font = SystemFonts.MessageBoxFont;
    92       treeView.Font = SystemFonts.MessageBoxFont;
    93       plotPanel.Font = SystemFonts.MessageBoxFont;
    94       
    95       nodeCheckBox.IsVisibleValueNeeded += nodeCheckBox_IsVisibleValueNeeded;
    96       nodeCheckBox.CheckStateChanged += UpdatePlotSelection;
    97       nodeTextBoxText.DrawText += nodeTextBoxText_DrawText;
    98       nodeTextBoxValue.DrawText += nodeTextBoxText_DrawText;
    99       nodeTextBoxMin.DrawText += nodeTextBoxText_DrawText;
   100       nodeTextBoxMax.DrawText += nodeTextBoxText_DrawText;
   101       nodeTextBoxText.EditorShowing += nodeTextBoxText_EditorShowing;
   102 
   103       foreach (TreeColumn column in treeView.Columns) 
   104         column.Width = Math.Max(20, Math.Min(400,
   105           settings.GetValue("treeView.Columns." + column.Header + ".Width",
   106           column.Width)));
   107 
   108       treeModel = new TreeModel();
   109       root = new Node(System.Environment.MachineName);
   110       root.Image = Utilities.EmbeddedResources.GetImage("computer.png");
   111       
   112       treeModel.Nodes.Add(root);
   113       treeView.Model = treeModel;
   114 
   115       this.computer = new Computer(settings);
   116 
   117       systemTray = new SystemTray(computer, settings);
   118       systemTray.HideShowCommand += hideShowClick;
   119       systemTray.ExitCommand += exitClick;
   120 
   121       int p = (int)Environment.OSVersion.Platform;
   122       if ((p == 4) || (p == 128)) { // Unix
   123         splitContainer.BorderStyle = BorderStyle.None;
   124         splitContainer.Border3DStyle = Border3DStyle.Adjust;
   125         splitContainer.SplitterWidth = 4;
   126         treeView.BorderStyle = BorderStyle.Fixed3D;
   127         plotPanel.BorderStyle = BorderStyle.Fixed3D;
   128         gadgetMenuItem.Visible = false;
   129         minCloseMenuItem.Visible = false;
   130       } else { // Windows
   131         gadget = new SensorGadget(computer, settings, unitManager);
   132         gadget.HideShowCommand += hideShowClick;
   133 
   134         wmiProvider = new WmiProvider(computer);
   135       }          
   136 
   137       computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
   138       computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);        
   139 
   140       computer.Open();
   141 
   142       timer.Enabled = true;
   143 
   144       plotColorPalette = new Color[13];
   145       plotColorPalette[0] = Color.Blue;
   146       plotColorPalette[1] = Color.OrangeRed;
   147       plotColorPalette[2] = Color.Green;
   148       plotColorPalette[3] = Color.LightSeaGreen;
   149       plotColorPalette[4] = Color.Goldenrod;
   150       plotColorPalette[5] = Color.DarkViolet;
   151       plotColorPalette[6] = Color.YellowGreen;
   152       plotColorPalette[7] = Color.SaddleBrown;
   153       plotColorPalette[8] = Color.RoyalBlue;
   154       plotColorPalette[9] = Color.DeepPink;
   155       plotColorPalette[10] = Color.MediumSeaGreen;
   156       plotColorPalette[11] = Color.Olive;
   157       plotColorPalette[12] = Color.Firebrick;
   158 
   159       showHiddenSensors = new UserOption("hiddenMenuItem", false,
   160         hiddenMenuItem, settings);
   161       showHiddenSensors.Changed += delegate(object sender, EventArgs e) {
   162         treeModel.ForceVisible = showHiddenSensors.Value;
   163       };
   164 
   165       showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings);
   166       showPlot.Changed += delegate(object sender, EventArgs e) {
   167         splitContainer.Panel2Collapsed = !showPlot.Value;
   168         treeView.Invalidate();
   169       };
   170 
   171       showValue = new UserOption("valueMenuItem", true, valueMenuItem,
   172         settings);
   173       showValue.Changed += delegate(object sender, EventArgs e) {
   174         treeView.Columns[1].IsVisible = showValue.Value;
   175       };
   176 
   177       showMin = new UserOption("minMenuItem", false, minMenuItem, settings);
   178       showMin.Changed += delegate(object sender, EventArgs e) {
   179         treeView.Columns[2].IsVisible = showMin.Value;
   180       };
   181 
   182       showMax = new UserOption("maxMenuItem", true, maxMenuItem, settings);
   183       showMax.Changed += delegate(object sender, EventArgs e) {
   184         treeView.Columns[3].IsVisible = showMax.Value;
   185       };
   186 
   187       startMinimized = new UserOption("startMinMenuItem", false,
   188         startMinMenuItem, settings);
   189 
   190       minimizeToTray = new UserOption("minTrayMenuItem", true,
   191         minTrayMenuItem, settings);
   192       minimizeToTray.Changed += delegate(object sender, EventArgs e) {
   193         systemTray.IsMainIconEnabled = minimizeToTray.Value;
   194       };
   195 
   196       minimizeOnClose = new UserOption("minCloseMenuItem", false,
   197         minCloseMenuItem, settings);
   198 
   199       autoStart = new UserOption(null, startupManager.Startup,
   200         startupMenuItem, settings);
   201       autoStart.Changed += delegate(object sender, EventArgs e) {
   202         try {
   203           startupManager.Startup = autoStart.Value;
   204         } catch (InvalidOperationException) {
   205           MessageBox.Show("Updating the auto-startup option failed.", "Error", 
   206             MessageBoxButtons.OK, MessageBoxIcon.Error);
   207           autoStart.Value = startupManager.Startup;
   208         }
   209       };
   210 
   211       readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem,
   212         settings);
   213       readHddSensors.Changed += delegate(object sender, EventArgs e) {
   214         computer.HDDEnabled = readHddSensors.Value;
   215         UpdatePlotSelection(null, null);
   216       };
   217 
   218       showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem,
   219         settings);
   220       showGadget.Changed += delegate(object sender, EventArgs e) {
   221         if (gadget != null) 
   222           gadget.Visible = showGadget.Value;
   223       };
   224 
   225       celciusMenuItem.Checked = 
   226         unitManager.TemperatureUnit == TemperatureUnit.Celcius;
   227       fahrenheitMenuItem.Checked = !celciusMenuItem.Checked;
   228 
   229       startupMenuItem.Visible = startupManager.IsAvailable;
   230       
   231       if (startMinMenuItem.Checked) {
   232         if (!minTrayMenuItem.Checked) {
   233           WindowState = FormWindowState.Minimized;
   234           Show();
   235         }
   236       } else {
   237         Show();
   238       }
   239 
   240       // Create a handle, otherwise calling Close() does not fire FormClosed     
   241       IntPtr handle = Handle;
   242 
   243       // Make sure the settings are saved when the user logs off
   244       Microsoft.Win32.SystemEvents.SessionEnded += delegate {
   245         SaveConfiguration();
   246       };  
   247     }
   248     
   249     private void SubHardwareAdded(IHardware hardware, Node node) {
   250       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   251       node.Nodes.Add(hardwareNode);
   252       foreach (IHardware subHardware in hardware.SubHardware)
   253         SubHardwareAdded(subHardware, hardwareNode);  
   254     }
   255 
   256     private void HardwareAdded(IHardware hardware) {
   257       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   258       root.Nodes.Add(hardwareNode);
   259       foreach (IHardware subHardware in hardware.SubHardware)
   260         SubHardwareAdded(subHardware, hardwareNode);     
   261     }
   262 
   263     private void HardwareRemoved(IHardware hardware) {      
   264       List<Node> nodesToRemove = new List<Node>();
   265       foreach (Node node in root.Nodes) {
   266         HardwareNode hardwareNode = node as HardwareNode;
   267         if (hardwareNode != null && hardwareNode.Hardware == hardware)
   268           nodesToRemove.Add(node);
   269       }
   270       foreach (Node node in nodesToRemove)
   271         root.Nodes.Remove(node);
   272     }
   273 
   274     private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {       
   275       Node node = e.Node.Tag as Node;
   276       if (node != null) {
   277         Color color;
   278         if (node.IsVisible) {
   279           SensorNode sensorNode = node as SensorNode;
   280           if (plotMenuItem.Checked && sensorNode != null &&
   281             sensorPlotColors.TryGetValue(sensorNode.Sensor, out color))
   282             e.TextColor = color;
   283         } else {
   284           e.TextColor = Color.DarkGray;
   285         }
   286       }
   287     }
   288 
   289     private void UpdatePlotSelection(object sender, 
   290       TreePathEventArgs e) 
   291     {
   292       List<ISensor> selected = new List<ISensor>();
   293       IDictionary<ISensor, Color> colors = new Dictionary<ISensor, Color>();
   294       int colorIndex = 0;
   295       foreach (TreeNodeAdv node in treeView.AllNodes) {
   296         SensorNode sensorNode = node.Tag as SensorNode;
   297         if (sensorNode != null && 
   298           sensorNode.Sensor.SensorType == SensorType.Temperature) {
   299           if (sensorNode.Plot) {
   300             colors.Add(sensorNode.Sensor,
   301               plotColorPalette[colorIndex % plotColorPalette.Length]);
   302             selected.Add(sensorNode.Sensor);
   303           }
   304           colorIndex++;
   305         }
   306       }
   307       sensorPlotColors = colors;
   308       plotPanel.SetSensors(selected, colors);
   309     }
   310 
   311     private void nodeTextBoxText_EditorShowing(object sender,
   312       CancelEventArgs e) 
   313     {
   314       e.Cancel = !(treeView.CurrentNode != null &&
   315         treeView.CurrentNode.Tag is SensorNode);
   316     }
   317 
   318     private void nodeCheckBox_IsVisibleValueNeeded(object sender, 
   319       NodeControlValueEventArgs e) {
   320       SensorNode node = e.Node.Tag as SensorNode;
   321       e.Value = (node != null) && 
   322         (node.Sensor.SensorType == SensorType.Temperature) && 
   323         plotMenuItem.Checked;
   324     }
   325 
   326     private void exitClick(object sender, EventArgs e) {
   327       Close();
   328     }
   329 
   330     private void timer_Tick(object sender, EventArgs e) {
   331       computer.Accept(updateVisitor);
   332       treeView.Invalidate();
   333       plotPanel.Invalidate();
   334       systemTray.Redraw();
   335       if (gadget != null)
   336         gadget.Redraw();
   337 
   338       if (wmiProvider != null)
   339         wmiProvider.Update();
   340     }
   341 
   342     private void SaveConfiguration() {
   343       foreach (TreeColumn column in treeView.Columns)
   344         settings.SetValue("treeView.Columns." + column.Header + ".Width",
   345           column.Width);
   346 
   347       string fileName = Path.ChangeExtension(
   348           System.Windows.Forms.Application.ExecutablePath, ".config");
   349       try {
   350         settings.Save(fileName);
   351       } catch (UnauthorizedAccessException) {
   352         MessageBox.Show("Access to the path '" + fileName + "' is denied. " +
   353           "The current seetings could not be saved.", 
   354           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
   355       }
   356     }
   357 
   358     private void MainForm_Load(object sender, EventArgs e) {
   359       Rectangle newBounds = new Rectangle {
   360         X = settings.GetValue("mainForm.Location.X", Location.X),
   361         Y = settings.GetValue("mainForm.Location.Y", Location.Y),
   362         Width = settings.GetValue("mainForm.Width", 470),
   363         Height = settings.GetValue("mainForm.Height", 640)
   364       };
   365 
   366       Rectangle fullWorkingArea = new Rectangle(int.MaxValue, int.MaxValue,
   367         int.MinValue, int.MinValue);
   368 
   369       foreach (Screen screen in Screen.AllScreens)
   370         fullWorkingArea = Rectangle.Union(fullWorkingArea, screen.Bounds);
   371 
   372       Rectangle intersection = Rectangle.Intersect(fullWorkingArea, newBounds);
   373       if (intersection.Width < 20 || intersection.Height < 20 ||
   374         !settings.Contains("mainForm.Location.X")
   375       ) {
   376         newBounds.X = (Screen.PrimaryScreen.WorkingArea.Width / 2) -
   377                       (newBounds.Width/2);
   378 
   379         newBounds.Y = (Screen.PrimaryScreen.WorkingArea.Height / 2) -
   380                       (newBounds.Height / 2);
   381       }
   382 
   383       this.Bounds = newBounds;
   384     }
   385     
   386     private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
   387       Visible = false;
   388       SaveConfiguration();
   389 
   390       timer.Enabled = false;
   391       systemTray.Dispose();      
   392       computer.Close();
   393     }
   394 
   395     private void aboutMenuItem_Click(object sender, EventArgs e) {
   396       new AboutBox().ShowDialog();
   397     }
   398 
   399     private void treeView_Click(object sender, EventArgs e) {
   400       
   401       MouseEventArgs m = e as MouseEventArgs;
   402       if (m == null || m.Button != MouseButtons.Right)
   403         return;
   404 
   405       NodeControlInfo info = treeView.GetNodeControlInfoAt(
   406         new Point(m.X, m.Y)
   407       );
   408       treeView.SelectedNode = info.Node;
   409       if (info.Node != null) {
   410         SensorNode node = info.Node.Tag as SensorNode;
   411         if (node != null && node.Sensor != null) {
   412           sensorContextMenu.MenuItems.Clear();
   413           if (node.Sensor.Parameters.Length > 0) {
   414             MenuItem item = new MenuItem("Parameters...");
   415             item.Click += delegate(object obj, EventArgs args) {
   416               ShowParameterForm(node.Sensor);
   417             };
   418             sensorContextMenu.MenuItems.Add(item);
   419           }
   420           if (nodeTextBoxText.EditEnabled) {
   421             MenuItem item = new MenuItem("Rename");
   422             item.Click += delegate(object obj, EventArgs args) {
   423               nodeTextBoxText.BeginEdit();
   424             };
   425             sensorContextMenu.MenuItems.Add(item);
   426           }
   427           if (node.IsVisible) {
   428             MenuItem item = new MenuItem("Hide");
   429             item.Click += delegate(object obj, EventArgs args) {
   430               node.IsVisible = false;
   431             };
   432             sensorContextMenu.MenuItems.Add(item);
   433           } else {
   434             MenuItem item = new MenuItem("Unhide");
   435             item.Click += delegate(object obj, EventArgs args) {
   436               node.IsVisible = true;
   437             };
   438             sensorContextMenu.MenuItems.Add(item);
   439           }
   440           sensorContextMenu.MenuItems.Add(new MenuItem("-"));
   441           {
   442             MenuItem item = new MenuItem("Show in Tray");
   443             item.Checked = systemTray.Contains(node.Sensor);
   444             item.Click += delegate(object obj, EventArgs args) {
   445               if (item.Checked)
   446                 systemTray.Remove(node.Sensor);
   447               else
   448                 systemTray.Add(node.Sensor, true);
   449             };
   450             sensorContextMenu.MenuItems.Add(item);
   451           }
   452           if (gadget != null) {
   453             MenuItem item = new MenuItem("Show in Gadget");
   454             item.Checked = gadget.Contains(node.Sensor);
   455             item.Click += delegate(object obj, EventArgs args) {
   456               if (item.Checked) {
   457                 gadget.Remove(node.Sensor);
   458               } else {
   459                 gadget.Add(node.Sensor);
   460               }
   461             };
   462             sensorContextMenu.MenuItems.Add(item);
   463           }
   464           if (node.Sensor.Control != null) {
   465             sensorContextMenu.MenuItems.Add(new MenuItem("-"));
   466             IControl control = node.Sensor.Control;
   467             MenuItem controlItem = new MenuItem("Control");
   468             MenuItem defaultItem = new MenuItem("Default");
   469             defaultItem.Checked = control.ControlMode == ControlMode.Default;
   470             controlItem.MenuItems.Add(defaultItem);
   471             defaultItem.Click += delegate(object obj, EventArgs args) {
   472               control.SetDefault();
   473             };
   474             MenuItem manualItem = new MenuItem("Manual");            
   475             controlItem.MenuItems.Add(manualItem);
   476             manualItem.Checked = control.ControlMode == ControlMode.Software;
   477             for (int i = 0; i <= 100; i += 5) {
   478               if (i <= control.MaxSoftwareValue &&
   479                   i >= control.MinSoftwareValue) 
   480               {
   481                 MenuItem item = new MenuItem(i + " %");
   482                 manualItem.MenuItems.Add(item);
   483                 item.Checked = control.ControlMode == ControlMode.Software &&
   484                   Math.Round(control.SoftwareValue) == i;
   485                 int softwareValue = i;
   486                 item.Click += delegate(object obj, EventArgs args) {
   487                   control.SetSoftware(softwareValue);
   488                 };
   489               }
   490             }
   491             sensorContextMenu.MenuItems.Add(controlItem);
   492           }
   493 
   494           sensorContextMenu.Show(treeView, new Point(m.X, m.Y));
   495         }
   496       }
   497     }
   498 
   499     private void saveReportMenuItem_Click(object sender, EventArgs e) {
   500       string report = computer.GetReport();
   501       if (saveFileDialog.ShowDialog() == DialogResult.OK) {
   502         using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) {
   503           w.Write(report);
   504         }
   505       }
   506     }
   507 
   508     private void SysTrayHideShow() {
   509       Visible = !Visible;
   510       if (Visible)
   511         Activate();    
   512     }
   513 
   514     protected override void WndProc(ref Message m) {
   515       const int WM_SYSCOMMAND = 0x112;
   516       const int SC_MINIMIZE = 0xF020;
   517       const int SC_CLOSE = 0xF060;
   518 
   519       if (minimizeToTray.Value && 
   520         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) {
   521         SysTrayHideShow();
   522       } else if(minimizeOnClose.Value && 
   523         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) {
   524         /*
   525          * Apparently the user wants to minimize rather than close
   526          * Now we still need to check if we're going to the tray or not
   527          * 
   528          * Note: the correct way to do this would be to send out SC_MINIMIZE,
   529          * but since the code here is so simple,
   530          * that would just be a waste of time.
   531          */
   532         if (minimizeToTray.Value)
   533           SysTrayHideShow();
   534         else
   535           WindowState = FormWindowState.Minimized;
   536       } else {      
   537         base.WndProc(ref m);
   538       }
   539     }
   540 
   541     private void hideShowClick(object sender, EventArgs e) {
   542       SysTrayHideShow();
   543     }
   544 
   545     private void ShowParameterForm(ISensor sensor) {
   546       ParameterForm form = new ParameterForm();
   547       form.Parameters = sensor.Parameters;
   548       form.captionLabel.Text = sensor.Name;
   549       form.ShowDialog();
   550     }
   551 
   552     private void treeView_NodeMouseDoubleClick(object sender, 
   553       TreeNodeAdvMouseEventArgs e) {
   554       SensorNode node = e.Node.Tag as SensorNode;
   555       if (node != null && node.Sensor != null && 
   556         node.Sensor.Parameters.Length > 0) {
   557         ShowParameterForm(node.Sensor);
   558       }
   559     }
   560 
   561     private void celciusMenuItem_Click(object sender, EventArgs e) {
   562       celciusMenuItem.Checked = true;
   563       fahrenheitMenuItem.Checked = false;
   564       unitManager.TemperatureUnit = TemperatureUnit.Celcius;
   565     }
   566 
   567     private void fahrenheitMenuItem_Click(object sender, EventArgs e) {
   568       celciusMenuItem.Checked = false;
   569       fahrenheitMenuItem.Checked = true;
   570       unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit;
   571     }
   572 
   573     private void sumbitReportMenuItem_Click(object sender, EventArgs e) 
   574     {
   575       ReportForm form = new ReportForm();
   576       form.Report = computer.GetReport();
   577       form.ShowDialog();      
   578     }
   579 
   580     private void resetMinMaxMenuItem_Click(object sender, EventArgs e) {
   581       computer.Accept(new SensorVisitor(delegate(ISensor sensor) {
   582         sensor.ResetMin();
   583         sensor.ResetMax();
   584       }));
   585     }
   586 
   587     private void MainForm_MoveOrResize(object sender, EventArgs e) {
   588       if (WindowState != FormWindowState.Minimized) {
   589         settings.SetValue("mainForm.Location.X", Bounds.X);
   590         settings.SetValue("mainForm.Location.Y", Bounds.Y);
   591         settings.SetValue("mainForm.Width", Bounds.Width);
   592         settings.SetValue("mainForm.Height", Bounds.Height);
   593       }
   594     }
   595   }
   596 }