Fixed Issue 204.
3 Version: MPL 1.1/GPL 2.0/LGPL 2.1
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
9 http://www.mozilla.org/MPL/
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.
15 The Original Code is the Open Hardware Monitor code.
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-2011
20 the Initial Developer. All Rights Reserved.
22 Contributor(s): Paul Werelds
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.
39 using System.Collections.Generic;
40 using System.ComponentModel;
43 using System.Windows.Forms;
44 using Aga.Controls.Tree;
45 using Aga.Controls.Tree.NodeControls;
46 using OpenHardwareMonitor.Hardware;
47 using OpenHardwareMonitor.WMI;
49 namespace OpenHardwareMonitor.GUI {
50 public partial class MainForm : Form {
52 private PersistentSettings settings;
53 private UnitManager unitManager;
54 private Computer computer;
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;
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;
77 private WmiProvider wmiProvider;
80 InitializeComponent();
82 this.settings = new PersistentSettings();
83 this.settings.Load(Path.ChangeExtension(
84 Application.ExecutablePath, ".config"));
86 this.unitManager = new UnitManager(settings);
88 // set the DockStyle here, to avoid conflicts with the MainMenu
89 this.splitContainer.Dock = DockStyle.Fill;
91 this.Font = SystemFonts.MessageBoxFont;
92 treeView.Font = SystemFonts.MessageBoxFont;
93 plotPanel.Font = SystemFonts.MessageBoxFont;
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;
103 foreach (TreeColumn column in treeView.Columns)
104 column.Width = Math.Max(20, Math.Min(400,
105 settings.GetValue("treeView.Columns." + column.Header + ".Width",
108 treeModel = new TreeModel();
109 root = new Node(System.Environment.MachineName);
110 root.Image = Utilities.EmbeddedResources.GetImage("computer.png");
112 treeModel.Nodes.Add(root);
113 treeView.Model = treeModel;
115 this.computer = new Computer(settings);
117 systemTray = new SystemTray(computer, settings);
118 systemTray.HideShowCommand += hideShowClick;
119 systemTray.ExitCommand += exitClick;
121 int p = (int)Environment.OSVersion.Platform;
122 if ((p == 4) || (p == 128)) { // Unix
123 treeView.RowHeight = Math.Max(treeView.RowHeight, 17);
124 splitContainer.BorderStyle = BorderStyle.None;
125 splitContainer.Border3DStyle = Border3DStyle.Adjust;
126 splitContainer.SplitterWidth = 4;
127 treeView.BorderStyle = BorderStyle.Fixed3D;
128 plotPanel.BorderStyle = BorderStyle.Fixed3D;
129 gadgetMenuItem.Visible = false;
130 minCloseMenuItem.Visible = false;
131 minTrayMenuItem.Visible = false;
132 startMinMenuItem.Visible = false;
134 treeView.RowHeight = Math.Max(treeView.Font.Height + 1, 17);
136 gadget = new SensorGadget(computer, settings, unitManager);
137 gadget.HideShowCommand += hideShowClick;
139 wmiProvider = new WmiProvider(computer);
142 computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
143 computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);
147 timer.Enabled = true;
149 plotColorPalette = new Color[13];
150 plotColorPalette[0] = Color.Blue;
151 plotColorPalette[1] = Color.OrangeRed;
152 plotColorPalette[2] = Color.Green;
153 plotColorPalette[3] = Color.LightSeaGreen;
154 plotColorPalette[4] = Color.Goldenrod;
155 plotColorPalette[5] = Color.DarkViolet;
156 plotColorPalette[6] = Color.YellowGreen;
157 plotColorPalette[7] = Color.SaddleBrown;
158 plotColorPalette[8] = Color.RoyalBlue;
159 plotColorPalette[9] = Color.DeepPink;
160 plotColorPalette[10] = Color.MediumSeaGreen;
161 plotColorPalette[11] = Color.Olive;
162 plotColorPalette[12] = Color.Firebrick;
164 showHiddenSensors = new UserOption("hiddenMenuItem", false,
165 hiddenMenuItem, settings);
166 showHiddenSensors.Changed += delegate(object sender, EventArgs e) {
167 treeModel.ForceVisible = showHiddenSensors.Value;
170 showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings);
171 showPlot.Changed += delegate(object sender, EventArgs e) {
172 splitContainer.Panel2Collapsed = !showPlot.Value;
173 treeView.Invalidate();
176 showValue = new UserOption("valueMenuItem", true, valueMenuItem,
178 showValue.Changed += delegate(object sender, EventArgs e) {
179 treeView.Columns[1].IsVisible = showValue.Value;
182 showMin = new UserOption("minMenuItem", false, minMenuItem, settings);
183 showMin.Changed += delegate(object sender, EventArgs e) {
184 treeView.Columns[2].IsVisible = showMin.Value;
187 showMax = new UserOption("maxMenuItem", true, maxMenuItem, settings);
188 showMax.Changed += delegate(object sender, EventArgs e) {
189 treeView.Columns[3].IsVisible = showMax.Value;
192 startMinimized = new UserOption("startMinMenuItem", false,
193 startMinMenuItem, settings);
195 minimizeToTray = new UserOption("minTrayMenuItem", true,
196 minTrayMenuItem, settings);
197 minimizeToTray.Changed += delegate(object sender, EventArgs e) {
198 systemTray.IsMainIconEnabled = minimizeToTray.Value;
201 minimizeOnClose = new UserOption("minCloseMenuItem", false,
202 minCloseMenuItem, settings);
204 autoStart = new UserOption(null, startupManager.Startup,
205 startupMenuItem, settings);
206 autoStart.Changed += delegate(object sender, EventArgs e) {
208 startupManager.Startup = autoStart.Value;
209 } catch (InvalidOperationException) {
210 MessageBox.Show("Updating the auto-startup option failed.", "Error",
211 MessageBoxButtons.OK, MessageBoxIcon.Error);
212 autoStart.Value = startupManager.Startup;
216 readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem,
218 readHddSensors.Changed += delegate(object sender, EventArgs e) {
219 computer.HDDEnabled = readHddSensors.Value;
220 UpdatePlotSelection(null, null);
223 showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem,
225 showGadget.Changed += delegate(object sender, EventArgs e) {
227 gadget.Visible = showGadget.Value;
230 celciusMenuItem.Checked =
231 unitManager.TemperatureUnit == TemperatureUnit.Celcius;
232 fahrenheitMenuItem.Checked = !celciusMenuItem.Checked;
234 startupMenuItem.Visible = startupManager.IsAvailable;
236 if (startMinMenuItem.Checked) {
237 if (!minTrayMenuItem.Checked) {
238 WindowState = FormWindowState.Minimized;
245 // Create a handle, otherwise calling Close() does not fire FormClosed
246 IntPtr handle = Handle;
248 // Make sure the settings are saved when the user logs off
249 Microsoft.Win32.SystemEvents.SessionEnded += delegate {
254 private void SubHardwareAdded(IHardware hardware, Node node) {
255 Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
256 node.Nodes.Add(hardwareNode);
257 foreach (IHardware subHardware in hardware.SubHardware)
258 SubHardwareAdded(subHardware, hardwareNode);
261 private void HardwareAdded(IHardware hardware) {
262 Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
263 root.Nodes.Add(hardwareNode);
264 foreach (IHardware subHardware in hardware.SubHardware)
265 SubHardwareAdded(subHardware, hardwareNode);
268 private void HardwareRemoved(IHardware hardware) {
269 List<Node> nodesToRemove = new List<Node>();
270 foreach (Node node in root.Nodes) {
271 HardwareNode hardwareNode = node as HardwareNode;
272 if (hardwareNode != null && hardwareNode.Hardware == hardware)
273 nodesToRemove.Add(node);
275 foreach (Node node in nodesToRemove)
276 root.Nodes.Remove(node);
279 private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {
280 Node node = e.Node.Tag as Node;
283 if (node.IsVisible) {
284 SensorNode sensorNode = node as SensorNode;
285 if (plotMenuItem.Checked && sensorNode != null &&
286 sensorPlotColors.TryGetValue(sensorNode.Sensor, out color))
289 e.TextColor = Color.DarkGray;
294 private void UpdatePlotSelection(object sender,
297 List<ISensor> selected = new List<ISensor>();
298 IDictionary<ISensor, Color> colors = new Dictionary<ISensor, Color>();
300 foreach (TreeNodeAdv node in treeView.AllNodes) {
301 SensorNode sensorNode = node.Tag as SensorNode;
302 if (sensorNode != null &&
303 sensorNode.Sensor.SensorType == SensorType.Temperature) {
304 if (sensorNode.Plot) {
305 colors.Add(sensorNode.Sensor,
306 plotColorPalette[colorIndex % plotColorPalette.Length]);
307 selected.Add(sensorNode.Sensor);
312 sensorPlotColors = colors;
313 plotPanel.SetSensors(selected, colors);
316 private void nodeTextBoxText_EditorShowing(object sender,
319 e.Cancel = !(treeView.CurrentNode != null &&
320 (treeView.CurrentNode.Tag is SensorNode ||
321 treeView.CurrentNode.Tag is HardwareNode));
324 private void nodeCheckBox_IsVisibleValueNeeded(object sender,
325 NodeControlValueEventArgs e) {
326 SensorNode node = e.Node.Tag as SensorNode;
327 e.Value = (node != null) &&
328 (node.Sensor.SensorType == SensorType.Temperature) &&
329 plotMenuItem.Checked;
332 private void exitClick(object sender, EventArgs e) {
336 private void timer_Tick(object sender, EventArgs e) {
337 computer.Accept(updateVisitor);
338 treeView.Invalidate();
339 plotPanel.Invalidate();
344 if (wmiProvider != null)
345 wmiProvider.Update();
348 private void SaveConfiguration() {
349 foreach (TreeColumn column in treeView.Columns)
350 settings.SetValue("treeView.Columns." + column.Header + ".Width",
353 string fileName = Path.ChangeExtension(
354 System.Windows.Forms.Application.ExecutablePath, ".config");
356 settings.Save(fileName);
357 } catch (UnauthorizedAccessException) {
358 MessageBox.Show("Access to the path '" + fileName + "' is denied. " +
359 "The current settings could not be saved.",
360 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
361 } catch (IOException) {
362 MessageBox.Show("The path '" + fileName + "' is not writeable. " +
363 "The current settings could not be saved.",
364 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
368 private void MainForm_Load(object sender, EventArgs e) {
369 Rectangle newBounds = new Rectangle {
370 X = settings.GetValue("mainForm.Location.X", Location.X),
371 Y = settings.GetValue("mainForm.Location.Y", Location.Y),
372 Width = settings.GetValue("mainForm.Width", 470),
373 Height = settings.GetValue("mainForm.Height", 640)
376 Rectangle fullWorkingArea = new Rectangle(int.MaxValue, int.MaxValue,
377 int.MinValue, int.MinValue);
379 foreach (Screen screen in Screen.AllScreens)
380 fullWorkingArea = Rectangle.Union(fullWorkingArea, screen.Bounds);
382 Rectangle intersection = Rectangle.Intersect(fullWorkingArea, newBounds);
383 if (intersection.Width < 20 || intersection.Height < 20 ||
384 !settings.Contains("mainForm.Location.X")
386 newBounds.X = (Screen.PrimaryScreen.WorkingArea.Width / 2) -
389 newBounds.Y = (Screen.PrimaryScreen.WorkingArea.Height / 2) -
390 (newBounds.Height / 2);
393 this.Bounds = newBounds;
396 private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
400 systemTray.IsMainIconEnabled = false;
401 timer.Enabled = false;
403 systemTray.Dispose();
406 private void aboutMenuItem_Click(object sender, EventArgs e) {
407 new AboutBox().ShowDialog();
410 private void treeView_Click(object sender, EventArgs e) {
412 MouseEventArgs m = e as MouseEventArgs;
413 if (m == null || m.Button != MouseButtons.Right)
416 NodeControlInfo info = treeView.GetNodeControlInfoAt(
419 treeView.SelectedNode = info.Node;
420 if (info.Node != null) {
421 SensorNode node = info.Node.Tag as SensorNode;
422 if (node != null && node.Sensor != null) {
423 treeContextMenu.MenuItems.Clear();
424 if (node.Sensor.Parameters.Length > 0) {
425 MenuItem item = new MenuItem("Parameters...");
426 item.Click += delegate(object obj, EventArgs args) {
427 ShowParameterForm(node.Sensor);
429 treeContextMenu.MenuItems.Add(item);
431 if (nodeTextBoxText.EditEnabled) {
432 MenuItem item = new MenuItem("Rename");
433 item.Click += delegate(object obj, EventArgs args) {
434 nodeTextBoxText.BeginEdit();
436 treeContextMenu.MenuItems.Add(item);
438 if (node.IsVisible) {
439 MenuItem item = new MenuItem("Hide");
440 item.Click += delegate(object obj, EventArgs args) {
441 node.IsVisible = false;
443 treeContextMenu.MenuItems.Add(item);
445 MenuItem item = new MenuItem("Unhide");
446 item.Click += delegate(object obj, EventArgs args) {
447 node.IsVisible = true;
449 treeContextMenu.MenuItems.Add(item);
451 treeContextMenu.MenuItems.Add(new MenuItem("-"));
453 MenuItem item = new MenuItem("Show in Tray");
454 item.Checked = systemTray.Contains(node.Sensor);
455 item.Click += delegate(object obj, EventArgs args) {
457 systemTray.Remove(node.Sensor);
459 systemTray.Add(node.Sensor, true);
461 treeContextMenu.MenuItems.Add(item);
463 if (gadget != null) {
464 MenuItem item = new MenuItem("Show in Gadget");
465 item.Checked = gadget.Contains(node.Sensor);
466 item.Click += delegate(object obj, EventArgs args) {
468 gadget.Remove(node.Sensor);
470 gadget.Add(node.Sensor);
473 treeContextMenu.MenuItems.Add(item);
475 if (node.Sensor.Control != null) {
476 treeContextMenu.MenuItems.Add(new MenuItem("-"));
477 IControl control = node.Sensor.Control;
478 MenuItem controlItem = new MenuItem("Control");
479 MenuItem defaultItem = new MenuItem("Default");
480 defaultItem.Checked = control.ControlMode == ControlMode.Default;
481 controlItem.MenuItems.Add(defaultItem);
482 defaultItem.Click += delegate(object obj, EventArgs args) {
483 control.SetDefault();
485 MenuItem manualItem = new MenuItem("Manual");
486 controlItem.MenuItems.Add(manualItem);
487 manualItem.Checked = control.ControlMode == ControlMode.Software;
488 for (int i = 0; i <= 100; i += 5) {
489 if (i <= control.MaxSoftwareValue &&
490 i >= control.MinSoftwareValue) {
491 MenuItem item = new MenuItem(i + " %");
492 manualItem.MenuItems.Add(item);
493 item.Checked = control.ControlMode == ControlMode.Software &&
494 Math.Round(control.SoftwareValue) == i;
495 int softwareValue = i;
496 item.Click += delegate(object obj, EventArgs args) {
497 control.SetSoftware(softwareValue);
501 treeContextMenu.MenuItems.Add(controlItem);
504 treeContextMenu.Show(treeView, new Point(m.X, m.Y));
507 HardwareNode hardwareNode = info.Node.Tag as HardwareNode;
508 if (hardwareNode != null && hardwareNode.Hardware != null) {
509 treeContextMenu.MenuItems.Clear();
511 if (nodeTextBoxText.EditEnabled) {
512 MenuItem item = new MenuItem("Rename");
513 item.Click += delegate(object obj, EventArgs args) {
514 nodeTextBoxText.BeginEdit();
516 treeContextMenu.MenuItems.Add(item);
519 treeContextMenu.Show(treeView, new Point(m.X, m.Y));
524 private void saveReportMenuItem_Click(object sender, EventArgs e) {
525 string report = computer.GetReport();
526 if (saveFileDialog.ShowDialog() == DialogResult.OK) {
527 using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) {
533 private void SysTrayHideShow() {
539 protected override void WndProc(ref Message m) {
540 const int WM_SYSCOMMAND = 0x112;
541 const int SC_MINIMIZE = 0xF020;
542 const int SC_CLOSE = 0xF060;
544 if (minimizeToTray.Value &&
545 m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) {
547 } else if(minimizeOnClose.Value &&
548 m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) {
550 * Apparently the user wants to minimize rather than close
551 * Now we still need to check if we're going to the tray or not
553 * Note: the correct way to do this would be to send out SC_MINIMIZE,
554 * but since the code here is so simple,
555 * that would just be a waste of time.
557 if (minimizeToTray.Value)
560 WindowState = FormWindowState.Minimized;
566 private void hideShowClick(object sender, EventArgs e) {
570 private void ShowParameterForm(ISensor sensor) {
571 ParameterForm form = new ParameterForm();
572 form.Parameters = sensor.Parameters;
573 form.captionLabel.Text = sensor.Name;
577 private void treeView_NodeMouseDoubleClick(object sender,
578 TreeNodeAdvMouseEventArgs e) {
579 SensorNode node = e.Node.Tag as SensorNode;
580 if (node != null && node.Sensor != null &&
581 node.Sensor.Parameters.Length > 0) {
582 ShowParameterForm(node.Sensor);
586 private void celciusMenuItem_Click(object sender, EventArgs e) {
587 celciusMenuItem.Checked = true;
588 fahrenheitMenuItem.Checked = false;
589 unitManager.TemperatureUnit = TemperatureUnit.Celcius;
592 private void fahrenheitMenuItem_Click(object sender, EventArgs e) {
593 celciusMenuItem.Checked = false;
594 fahrenheitMenuItem.Checked = true;
595 unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit;
598 private void sumbitReportMenuItem_Click(object sender, EventArgs e)
600 ReportForm form = new ReportForm();
601 form.Report = computer.GetReport();
605 private void resetMinMaxMenuItem_Click(object sender, EventArgs e) {
606 computer.Accept(new SensorVisitor(delegate(ISensor sensor) {
612 private void MainForm_MoveOrResize(object sender, EventArgs e) {
613 if (WindowState != FormWindowState.Minimized) {
614 settings.SetValue("mainForm.Location.X", Bounds.X);
615 settings.SetValue("mainForm.Location.Y", Bounds.Y);
616 settings.SetValue("mainForm.Width", Bounds.Width);
617 settings.SetValue("mainForm.Height", Bounds.Height);
621 private void resetClick(object sender, EventArgs e) {
622 // disable the fallback MainIcon during reset, otherwise icon visibility
624 systemTray.IsMainIconEnabled = false;
627 // restore the MainIcon setting
628 systemTray.IsMainIconEnabled = minimizeToTray.Value;