Fixed Issue 224.
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.Reflection;
44 using System.Windows.Forms;
45 using Aga.Controls.Tree;
46 using Aga.Controls.Tree.NodeControls;
47 using OpenHardwareMonitor.Hardware;
48 using OpenHardwareMonitor.WMI;
50 namespace OpenHardwareMonitor.GUI {
51 public partial class MainForm : Form {
53 private PersistentSettings settings;
54 private UnitManager unitManager;
55 private Computer computer;
57 private TreeModel treeModel;
58 private IDictionary<ISensor, Color> sensorPlotColors =
59 new Dictionary<ISensor, Color>();
60 private Color[] plotColorPalette;
61 private SystemTray systemTray;
62 private StartupManager startupManager = new StartupManager();
63 private UpdateVisitor updateVisitor = new UpdateVisitor();
64 private SensorGadget gadget;
66 private UserOption showHiddenSensors;
67 private UserOption showPlot;
68 private UserOption showValue;
69 private UserOption showMin;
70 private UserOption showMax;
71 private UserOption startMinimized;
72 private UserOption minimizeToTray;
73 private UserOption minimizeOnClose;
74 private UserOption autoStart;
75 private UserOption readHddSensors;
76 private UserOption showGadget;
78 private WmiProvider wmiProvider;
80 private bool selectionDragging = false;
83 InitializeComponent();
85 // check if the OpenHardwareMonitorLib assembly has the correct version
86 if (Assembly.GetAssembly(typeof(Computer)).GetName().Version !=
87 Assembly.GetExecutingAssembly().GetName().Version) {
89 "The version of the file OpenHardwareMonitorLib.dll is incompatible.",
90 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
94 this.settings = new PersistentSettings();
95 this.settings.Load(Path.ChangeExtension(
96 Application.ExecutablePath, ".config"));
98 this.unitManager = new UnitManager(settings);
100 // set the DockStyle here, to avoid conflicts with the MainMenu
101 this.splitContainer.Dock = DockStyle.Fill;
103 this.Font = SystemFonts.MessageBoxFont;
104 treeView.Font = SystemFonts.MessageBoxFont;
105 plotPanel.Font = SystemFonts.MessageBoxFont;
107 nodeCheckBox.IsVisibleValueNeeded += nodeCheckBox_IsVisibleValueNeeded;
108 nodeCheckBox.CheckStateChanged += UpdatePlotSelection;
109 nodeTextBoxText.DrawText += nodeTextBoxText_DrawText;
110 nodeTextBoxValue.DrawText += nodeTextBoxText_DrawText;
111 nodeTextBoxMin.DrawText += nodeTextBoxText_DrawText;
112 nodeTextBoxMax.DrawText += nodeTextBoxText_DrawText;
113 nodeTextBoxText.EditorShowing += nodeTextBoxText_EditorShowing;
115 foreach (TreeColumn column in treeView.Columns)
116 column.Width = Math.Max(20, Math.Min(400,
117 settings.GetValue("treeView.Columns." + column.Header + ".Width",
120 treeModel = new TreeModel();
121 root = new Node(System.Environment.MachineName);
122 root.Image = Utilities.EmbeddedResources.GetImage("computer.png");
124 treeModel.Nodes.Add(root);
125 treeView.Model = treeModel;
127 this.computer = new Computer(settings);
129 systemTray = new SystemTray(computer, settings);
130 systemTray.HideShowCommand += hideShowClick;
131 systemTray.ExitCommand += exitClick;
133 int p = (int)Environment.OSVersion.Platform;
134 if ((p == 4) || (p == 128)) { // Unix
135 treeView.RowHeight = Math.Max(treeView.RowHeight, 18);
136 splitContainer.BorderStyle = BorderStyle.None;
137 splitContainer.Border3DStyle = Border3DStyle.Adjust;
138 splitContainer.SplitterWidth = 4;
139 treeView.BorderStyle = BorderStyle.Fixed3D;
140 plotPanel.BorderStyle = BorderStyle.Fixed3D;
141 gadgetMenuItem.Visible = false;
142 minCloseMenuItem.Visible = false;
143 minTrayMenuItem.Visible = false;
144 startMinMenuItem.Visible = false;
146 treeView.RowHeight = Math.Max(treeView.Font.Height + 1, 18);
148 gadget = new SensorGadget(computer, settings, unitManager);
149 gadget.HideShowCommand += hideShowClick;
151 wmiProvider = new WmiProvider(computer);
154 computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
155 computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);
159 timer.Enabled = true;
161 plotColorPalette = new Color[13];
162 plotColorPalette[0] = Color.Blue;
163 plotColorPalette[1] = Color.OrangeRed;
164 plotColorPalette[2] = Color.Green;
165 plotColorPalette[3] = Color.LightSeaGreen;
166 plotColorPalette[4] = Color.Goldenrod;
167 plotColorPalette[5] = Color.DarkViolet;
168 plotColorPalette[6] = Color.YellowGreen;
169 plotColorPalette[7] = Color.SaddleBrown;
170 plotColorPalette[8] = Color.RoyalBlue;
171 plotColorPalette[9] = Color.DeepPink;
172 plotColorPalette[10] = Color.MediumSeaGreen;
173 plotColorPalette[11] = Color.Olive;
174 plotColorPalette[12] = Color.Firebrick;
176 showHiddenSensors = new UserOption("hiddenMenuItem", false,
177 hiddenMenuItem, settings);
178 showHiddenSensors.Changed += delegate(object sender, EventArgs e) {
179 treeModel.ForceVisible = showHiddenSensors.Value;
182 showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings);
183 showPlot.Changed += delegate(object sender, EventArgs e) {
184 splitContainer.Panel2Collapsed = !showPlot.Value;
185 treeView.Invalidate();
188 showValue = new UserOption("valueMenuItem", true, valueMenuItem,
190 showValue.Changed += delegate(object sender, EventArgs e) {
191 treeView.Columns[1].IsVisible = showValue.Value;
194 showMin = new UserOption("minMenuItem", false, minMenuItem, settings);
195 showMin.Changed += delegate(object sender, EventArgs e) {
196 treeView.Columns[2].IsVisible = showMin.Value;
199 showMax = new UserOption("maxMenuItem", true, maxMenuItem, settings);
200 showMax.Changed += delegate(object sender, EventArgs e) {
201 treeView.Columns[3].IsVisible = showMax.Value;
204 startMinimized = new UserOption("startMinMenuItem", false,
205 startMinMenuItem, settings);
207 minimizeToTray = new UserOption("minTrayMenuItem", true,
208 minTrayMenuItem, settings);
209 minimizeToTray.Changed += delegate(object sender, EventArgs e) {
210 systemTray.IsMainIconEnabled = minimizeToTray.Value;
213 minimizeOnClose = new UserOption("minCloseMenuItem", false,
214 minCloseMenuItem, settings);
216 autoStart = new UserOption(null, startupManager.Startup,
217 startupMenuItem, settings);
218 autoStart.Changed += delegate(object sender, EventArgs e) {
220 startupManager.Startup = autoStart.Value;
221 } catch (InvalidOperationException) {
222 MessageBox.Show("Updating the auto-startup option failed.", "Error",
223 MessageBoxButtons.OK, MessageBoxIcon.Error);
224 autoStart.Value = startupManager.Startup;
228 readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem,
230 readHddSensors.Changed += delegate(object sender, EventArgs e) {
231 computer.HDDEnabled = readHddSensors.Value;
232 UpdatePlotSelection(null, null);
235 showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem,
237 showGadget.Changed += delegate(object sender, EventArgs e) {
239 gadget.Visible = showGadget.Value;
242 celciusMenuItem.Checked =
243 unitManager.TemperatureUnit == TemperatureUnit.Celcius;
244 fahrenheitMenuItem.Checked = !celciusMenuItem.Checked;
246 startupMenuItem.Visible = startupManager.IsAvailable;
248 if (startMinMenuItem.Checked) {
249 if (!minTrayMenuItem.Checked) {
250 WindowState = FormWindowState.Minimized;
257 // Create a handle, otherwise calling Close() does not fire FormClosed
258 IntPtr handle = Handle;
260 // Make sure the settings are saved when the user logs off
261 Microsoft.Win32.SystemEvents.SessionEnded += delegate {
266 private void SubHardwareAdded(IHardware hardware, Node node) {
267 Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
268 node.Nodes.Add(hardwareNode);
269 foreach (IHardware subHardware in hardware.SubHardware)
270 SubHardwareAdded(subHardware, hardwareNode);
273 private void HardwareAdded(IHardware hardware) {
274 Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
275 root.Nodes.Add(hardwareNode);
276 foreach (IHardware subHardware in hardware.SubHardware)
277 SubHardwareAdded(subHardware, hardwareNode);
280 private void HardwareRemoved(IHardware hardware) {
281 List<Node> nodesToRemove = new List<Node>();
282 foreach (Node node in root.Nodes) {
283 HardwareNode hardwareNode = node as HardwareNode;
284 if (hardwareNode != null && hardwareNode.Hardware == hardware)
285 nodesToRemove.Add(node);
287 foreach (Node node in nodesToRemove)
288 root.Nodes.Remove(node);
291 private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {
292 Node node = e.Node.Tag as Node;
295 if (node.IsVisible) {
296 SensorNode sensorNode = node as SensorNode;
297 if (plotMenuItem.Checked && sensorNode != null &&
298 sensorPlotColors.TryGetValue(sensorNode.Sensor, out color))
301 e.TextColor = Color.DarkGray;
306 private void UpdatePlotSelection(object sender,
309 List<ISensor> selected = new List<ISensor>();
310 IDictionary<ISensor, Color> colors = new Dictionary<ISensor, Color>();
312 foreach (TreeNodeAdv node in treeView.AllNodes) {
313 SensorNode sensorNode = node.Tag as SensorNode;
314 if (sensorNode != null &&
315 sensorNode.Sensor.SensorType == SensorType.Temperature) {
316 if (sensorNode.Plot) {
317 colors.Add(sensorNode.Sensor,
318 plotColorPalette[colorIndex % plotColorPalette.Length]);
319 selected.Add(sensorNode.Sensor);
324 sensorPlotColors = colors;
325 plotPanel.SetSensors(selected, colors);
328 private void nodeTextBoxText_EditorShowing(object sender,
331 e.Cancel = !(treeView.CurrentNode != null &&
332 (treeView.CurrentNode.Tag is SensorNode ||
333 treeView.CurrentNode.Tag is HardwareNode));
336 private void nodeCheckBox_IsVisibleValueNeeded(object sender,
337 NodeControlValueEventArgs e) {
338 SensorNode node = e.Node.Tag as SensorNode;
339 e.Value = (node != null) &&
340 (node.Sensor.SensorType == SensorType.Temperature) &&
341 plotMenuItem.Checked;
344 private void exitClick(object sender, EventArgs e) {
348 private void timer_Tick(object sender, EventArgs e) {
349 computer.Accept(updateVisitor);
350 treeView.Invalidate();
351 plotPanel.Invalidate();
356 if (wmiProvider != null)
357 wmiProvider.Update();
360 private void SaveConfiguration() {
361 foreach (TreeColumn column in treeView.Columns)
362 settings.SetValue("treeView.Columns." + column.Header + ".Width",
365 string fileName = Path.ChangeExtension(
366 System.Windows.Forms.Application.ExecutablePath, ".config");
368 settings.Save(fileName);
369 } catch (UnauthorizedAccessException) {
370 MessageBox.Show("Access to the path '" + fileName + "' is denied. " +
371 "The current settings could not be saved.",
372 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
373 } catch (IOException) {
374 MessageBox.Show("The path '" + fileName + "' is not writeable. " +
375 "The current settings could not be saved.",
376 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
380 private void MainForm_Load(object sender, EventArgs e) {
381 Rectangle newBounds = new Rectangle {
382 X = settings.GetValue("mainForm.Location.X", Location.X),
383 Y = settings.GetValue("mainForm.Location.Y", Location.Y),
384 Width = settings.GetValue("mainForm.Width", 470),
385 Height = settings.GetValue("mainForm.Height", 640)
388 Rectangle fullWorkingArea = new Rectangle(int.MaxValue, int.MaxValue,
389 int.MinValue, int.MinValue);
391 foreach (Screen screen in Screen.AllScreens)
392 fullWorkingArea = Rectangle.Union(fullWorkingArea, screen.Bounds);
394 Rectangle intersection = Rectangle.Intersect(fullWorkingArea, newBounds);
395 if (intersection.Width < 20 || intersection.Height < 20 ||
396 !settings.Contains("mainForm.Location.X")
398 newBounds.X = (Screen.PrimaryScreen.WorkingArea.Width / 2) -
401 newBounds.Y = (Screen.PrimaryScreen.WorkingArea.Height / 2) -
402 (newBounds.Height / 2);
405 this.Bounds = newBounds;
408 private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
412 systemTray.IsMainIconEnabled = false;
413 timer.Enabled = false;
415 systemTray.Dispose();
418 private void aboutMenuItem_Click(object sender, EventArgs e) {
419 new AboutBox().ShowDialog();
422 private void treeView_Click(object sender, EventArgs e) {
424 MouseEventArgs m = e as MouseEventArgs;
425 if (m == null || m.Button != MouseButtons.Right)
428 NodeControlInfo info = treeView.GetNodeControlInfoAt(
431 treeView.SelectedNode = info.Node;
432 if (info.Node != null) {
433 SensorNode node = info.Node.Tag as SensorNode;
434 if (node != null && node.Sensor != null) {
435 treeContextMenu.MenuItems.Clear();
436 if (node.Sensor.Parameters.Length > 0) {
437 MenuItem item = new MenuItem("Parameters...");
438 item.Click += delegate(object obj, EventArgs args) {
439 ShowParameterForm(node.Sensor);
441 treeContextMenu.MenuItems.Add(item);
443 if (nodeTextBoxText.EditEnabled) {
444 MenuItem item = new MenuItem("Rename");
445 item.Click += delegate(object obj, EventArgs args) {
446 nodeTextBoxText.BeginEdit();
448 treeContextMenu.MenuItems.Add(item);
450 if (node.IsVisible) {
451 MenuItem item = new MenuItem("Hide");
452 item.Click += delegate(object obj, EventArgs args) {
453 node.IsVisible = false;
455 treeContextMenu.MenuItems.Add(item);
457 MenuItem item = new MenuItem("Unhide");
458 item.Click += delegate(object obj, EventArgs args) {
459 node.IsVisible = true;
461 treeContextMenu.MenuItems.Add(item);
463 treeContextMenu.MenuItems.Add(new MenuItem("-"));
465 MenuItem item = new MenuItem("Show in Tray");
466 item.Checked = systemTray.Contains(node.Sensor);
467 item.Click += delegate(object obj, EventArgs args) {
469 systemTray.Remove(node.Sensor);
471 systemTray.Add(node.Sensor, true);
473 treeContextMenu.MenuItems.Add(item);
475 if (gadget != null) {
476 MenuItem item = new MenuItem("Show in Gadget");
477 item.Checked = gadget.Contains(node.Sensor);
478 item.Click += delegate(object obj, EventArgs args) {
480 gadget.Remove(node.Sensor);
482 gadget.Add(node.Sensor);
485 treeContextMenu.MenuItems.Add(item);
487 if (node.Sensor.Control != null) {
488 treeContextMenu.MenuItems.Add(new MenuItem("-"));
489 IControl control = node.Sensor.Control;
490 MenuItem controlItem = new MenuItem("Control");
491 MenuItem defaultItem = new MenuItem("Default");
492 defaultItem.Checked = control.ControlMode == ControlMode.Default;
493 controlItem.MenuItems.Add(defaultItem);
494 defaultItem.Click += delegate(object obj, EventArgs args) {
495 control.SetDefault();
497 MenuItem manualItem = new MenuItem("Manual");
498 controlItem.MenuItems.Add(manualItem);
499 manualItem.Checked = control.ControlMode == ControlMode.Software;
500 for (int i = 0; i <= 100; i += 5) {
501 if (i <= control.MaxSoftwareValue &&
502 i >= control.MinSoftwareValue) {
503 MenuItem item = new MenuItem(i + " %");
504 manualItem.MenuItems.Add(item);
505 item.Checked = control.ControlMode == ControlMode.Software &&
506 Math.Round(control.SoftwareValue) == i;
507 int softwareValue = i;
508 item.Click += delegate(object obj, EventArgs args) {
509 control.SetSoftware(softwareValue);
513 treeContextMenu.MenuItems.Add(controlItem);
516 treeContextMenu.Show(treeView, new Point(m.X, m.Y));
519 HardwareNode hardwareNode = info.Node.Tag as HardwareNode;
520 if (hardwareNode != null && hardwareNode.Hardware != null) {
521 treeContextMenu.MenuItems.Clear();
523 if (nodeTextBoxText.EditEnabled) {
524 MenuItem item = new MenuItem("Rename");
525 item.Click += delegate(object obj, EventArgs args) {
526 nodeTextBoxText.BeginEdit();
528 treeContextMenu.MenuItems.Add(item);
531 treeContextMenu.Show(treeView, new Point(m.X, m.Y));
536 private void saveReportMenuItem_Click(object sender, EventArgs e) {
537 string report = computer.GetReport();
538 if (saveFileDialog.ShowDialog() == DialogResult.OK) {
539 using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) {
545 private void SysTrayHideShow() {
551 protected override void WndProc(ref Message m) {
552 const int WM_SYSCOMMAND = 0x112;
553 const int SC_MINIMIZE = 0xF020;
554 const int SC_CLOSE = 0xF060;
556 if (minimizeToTray.Value &&
557 m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) {
559 } else if(minimizeOnClose.Value &&
560 m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) {
562 * Apparently the user wants to minimize rather than close
563 * Now we still need to check if we're going to the tray or not
565 * Note: the correct way to do this would be to send out SC_MINIMIZE,
566 * but since the code here is so simple,
567 * that would just be a waste of time.
569 if (minimizeToTray.Value)
572 WindowState = FormWindowState.Minimized;
578 private void hideShowClick(object sender, EventArgs e) {
582 private void ShowParameterForm(ISensor sensor) {
583 ParameterForm form = new ParameterForm();
584 form.Parameters = sensor.Parameters;
585 form.captionLabel.Text = sensor.Name;
589 private void treeView_NodeMouseDoubleClick(object sender,
590 TreeNodeAdvMouseEventArgs e) {
591 SensorNode node = e.Node.Tag as SensorNode;
592 if (node != null && node.Sensor != null &&
593 node.Sensor.Parameters.Length > 0) {
594 ShowParameterForm(node.Sensor);
598 private void celciusMenuItem_Click(object sender, EventArgs e) {
599 celciusMenuItem.Checked = true;
600 fahrenheitMenuItem.Checked = false;
601 unitManager.TemperatureUnit = TemperatureUnit.Celcius;
604 private void fahrenheitMenuItem_Click(object sender, EventArgs e) {
605 celciusMenuItem.Checked = false;
606 fahrenheitMenuItem.Checked = true;
607 unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit;
610 private void sumbitReportMenuItem_Click(object sender, EventArgs e)
612 ReportForm form = new ReportForm();
613 form.Report = computer.GetReport();
617 private void resetMinMaxMenuItem_Click(object sender, EventArgs e) {
618 computer.Accept(new SensorVisitor(delegate(ISensor sensor) {
624 private void MainForm_MoveOrResize(object sender, EventArgs e) {
625 if (WindowState != FormWindowState.Minimized) {
626 settings.SetValue("mainForm.Location.X", Bounds.X);
627 settings.SetValue("mainForm.Location.Y", Bounds.Y);
628 settings.SetValue("mainForm.Width", Bounds.Width);
629 settings.SetValue("mainForm.Height", Bounds.Height);
633 private void resetClick(object sender, EventArgs e) {
634 // disable the fallback MainIcon during reset, otherwise icon visibility
636 systemTray.IsMainIconEnabled = false;
639 // restore the MainIcon setting
640 systemTray.IsMainIconEnabled = minimizeToTray.Value;
643 private void treeView_MouseMove(object sender, MouseEventArgs e) {
644 selectionDragging = selectionDragging &
645 (e.Button & (MouseButtons.Left | MouseButtons.Right)) > 0;
647 if (selectionDragging)
648 treeView.SelectedNode = treeView.GetNodeAt(e.Location);
651 private void treeView_MouseDown(object sender, MouseEventArgs e) {
652 selectionDragging = true;
655 private void treeView_MouseUp(object sender, MouseEventArgs e) {
656 selectionDragging = false;