Fixed Issue 215.
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;
79 private bool selectionDragging = false;
82 InitializeComponent();
84 this.settings = new PersistentSettings();
85 this.settings.Load(Path.ChangeExtension(
86 Application.ExecutablePath, ".config"));
88 this.unitManager = new UnitManager(settings);
90 // set the DockStyle here, to avoid conflicts with the MainMenu
91 this.splitContainer.Dock = DockStyle.Fill;
93 this.Font = SystemFonts.MessageBoxFont;
94 treeView.Font = SystemFonts.MessageBoxFont;
95 plotPanel.Font = SystemFonts.MessageBoxFont;
97 nodeCheckBox.IsVisibleValueNeeded += nodeCheckBox_IsVisibleValueNeeded;
98 nodeCheckBox.CheckStateChanged += UpdatePlotSelection;
99 nodeTextBoxText.DrawText += nodeTextBoxText_DrawText;
100 nodeTextBoxValue.DrawText += nodeTextBoxText_DrawText;
101 nodeTextBoxMin.DrawText += nodeTextBoxText_DrawText;
102 nodeTextBoxMax.DrawText += nodeTextBoxText_DrawText;
103 nodeTextBoxText.EditorShowing += nodeTextBoxText_EditorShowing;
105 foreach (TreeColumn column in treeView.Columns)
106 column.Width = Math.Max(20, Math.Min(400,
107 settings.GetValue("treeView.Columns." + column.Header + ".Width",
110 treeModel = new TreeModel();
111 root = new Node(System.Environment.MachineName);
112 root.Image = Utilities.EmbeddedResources.GetImage("computer.png");
114 treeModel.Nodes.Add(root);
115 treeView.Model = treeModel;
117 this.computer = new Computer(settings);
119 systemTray = new SystemTray(computer, settings);
120 systemTray.HideShowCommand += hideShowClick;
121 systemTray.ExitCommand += exitClick;
123 int p = (int)Environment.OSVersion.Platform;
124 if ((p == 4) || (p == 128)) { // Unix
125 treeView.RowHeight = Math.Max(treeView.RowHeight, 18);
126 splitContainer.BorderStyle = BorderStyle.None;
127 splitContainer.Border3DStyle = Border3DStyle.Adjust;
128 splitContainer.SplitterWidth = 4;
129 treeView.BorderStyle = BorderStyle.Fixed3D;
130 plotPanel.BorderStyle = BorderStyle.Fixed3D;
131 gadgetMenuItem.Visible = false;
132 minCloseMenuItem.Visible = false;
133 minTrayMenuItem.Visible = false;
134 startMinMenuItem.Visible = false;
136 treeView.RowHeight = Math.Max(treeView.Font.Height + 1, 18);
138 gadget = new SensorGadget(computer, settings, unitManager);
139 gadget.HideShowCommand += hideShowClick;
141 wmiProvider = new WmiProvider(computer);
144 computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
145 computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);
149 timer.Enabled = true;
151 plotColorPalette = new Color[13];
152 plotColorPalette[0] = Color.Blue;
153 plotColorPalette[1] = Color.OrangeRed;
154 plotColorPalette[2] = Color.Green;
155 plotColorPalette[3] = Color.LightSeaGreen;
156 plotColorPalette[4] = Color.Goldenrod;
157 plotColorPalette[5] = Color.DarkViolet;
158 plotColorPalette[6] = Color.YellowGreen;
159 plotColorPalette[7] = Color.SaddleBrown;
160 plotColorPalette[8] = Color.RoyalBlue;
161 plotColorPalette[9] = Color.DeepPink;
162 plotColorPalette[10] = Color.MediumSeaGreen;
163 plotColorPalette[11] = Color.Olive;
164 plotColorPalette[12] = Color.Firebrick;
166 showHiddenSensors = new UserOption("hiddenMenuItem", false,
167 hiddenMenuItem, settings);
168 showHiddenSensors.Changed += delegate(object sender, EventArgs e) {
169 treeModel.ForceVisible = showHiddenSensors.Value;
172 showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings);
173 showPlot.Changed += delegate(object sender, EventArgs e) {
174 splitContainer.Panel2Collapsed = !showPlot.Value;
175 treeView.Invalidate();
178 showValue = new UserOption("valueMenuItem", true, valueMenuItem,
180 showValue.Changed += delegate(object sender, EventArgs e) {
181 treeView.Columns[1].IsVisible = showValue.Value;
184 showMin = new UserOption("minMenuItem", false, minMenuItem, settings);
185 showMin.Changed += delegate(object sender, EventArgs e) {
186 treeView.Columns[2].IsVisible = showMin.Value;
189 showMax = new UserOption("maxMenuItem", true, maxMenuItem, settings);
190 showMax.Changed += delegate(object sender, EventArgs e) {
191 treeView.Columns[3].IsVisible = showMax.Value;
194 startMinimized = new UserOption("startMinMenuItem", false,
195 startMinMenuItem, settings);
197 minimizeToTray = new UserOption("minTrayMenuItem", true,
198 minTrayMenuItem, settings);
199 minimizeToTray.Changed += delegate(object sender, EventArgs e) {
200 systemTray.IsMainIconEnabled = minimizeToTray.Value;
203 minimizeOnClose = new UserOption("minCloseMenuItem", false,
204 minCloseMenuItem, settings);
206 autoStart = new UserOption(null, startupManager.Startup,
207 startupMenuItem, settings);
208 autoStart.Changed += delegate(object sender, EventArgs e) {
210 startupManager.Startup = autoStart.Value;
211 } catch (InvalidOperationException) {
212 MessageBox.Show("Updating the auto-startup option failed.", "Error",
213 MessageBoxButtons.OK, MessageBoxIcon.Error);
214 autoStart.Value = startupManager.Startup;
218 readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem,
220 readHddSensors.Changed += delegate(object sender, EventArgs e) {
221 computer.HDDEnabled = readHddSensors.Value;
222 UpdatePlotSelection(null, null);
225 showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem,
227 showGadget.Changed += delegate(object sender, EventArgs e) {
229 gadget.Visible = showGadget.Value;
232 celciusMenuItem.Checked =
233 unitManager.TemperatureUnit == TemperatureUnit.Celcius;
234 fahrenheitMenuItem.Checked = !celciusMenuItem.Checked;
236 startupMenuItem.Visible = startupManager.IsAvailable;
238 if (startMinMenuItem.Checked) {
239 if (!minTrayMenuItem.Checked) {
240 WindowState = FormWindowState.Minimized;
247 // Create a handle, otherwise calling Close() does not fire FormClosed
248 IntPtr handle = Handle;
250 // Make sure the settings are saved when the user logs off
251 Microsoft.Win32.SystemEvents.SessionEnded += delegate {
256 private void SubHardwareAdded(IHardware hardware, Node node) {
257 Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
258 node.Nodes.Add(hardwareNode);
259 foreach (IHardware subHardware in hardware.SubHardware)
260 SubHardwareAdded(subHardware, hardwareNode);
263 private void HardwareAdded(IHardware hardware) {
264 Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
265 root.Nodes.Add(hardwareNode);
266 foreach (IHardware subHardware in hardware.SubHardware)
267 SubHardwareAdded(subHardware, hardwareNode);
270 private void HardwareRemoved(IHardware hardware) {
271 List<Node> nodesToRemove = new List<Node>();
272 foreach (Node node in root.Nodes) {
273 HardwareNode hardwareNode = node as HardwareNode;
274 if (hardwareNode != null && hardwareNode.Hardware == hardware)
275 nodesToRemove.Add(node);
277 foreach (Node node in nodesToRemove)
278 root.Nodes.Remove(node);
281 private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {
282 Node node = e.Node.Tag as Node;
285 if (node.IsVisible) {
286 SensorNode sensorNode = node as SensorNode;
287 if (plotMenuItem.Checked && sensorNode != null &&
288 sensorPlotColors.TryGetValue(sensorNode.Sensor, out color))
291 e.TextColor = Color.DarkGray;
296 private void UpdatePlotSelection(object sender,
299 List<ISensor> selected = new List<ISensor>();
300 IDictionary<ISensor, Color> colors = new Dictionary<ISensor, Color>();
302 foreach (TreeNodeAdv node in treeView.AllNodes) {
303 SensorNode sensorNode = node.Tag as SensorNode;
304 if (sensorNode != null &&
305 sensorNode.Sensor.SensorType == SensorType.Temperature) {
306 if (sensorNode.Plot) {
307 colors.Add(sensorNode.Sensor,
308 plotColorPalette[colorIndex % plotColorPalette.Length]);
309 selected.Add(sensorNode.Sensor);
314 sensorPlotColors = colors;
315 plotPanel.SetSensors(selected, colors);
318 private void nodeTextBoxText_EditorShowing(object sender,
321 e.Cancel = !(treeView.CurrentNode != null &&
322 (treeView.CurrentNode.Tag is SensorNode ||
323 treeView.CurrentNode.Tag is HardwareNode));
326 private void nodeCheckBox_IsVisibleValueNeeded(object sender,
327 NodeControlValueEventArgs e) {
328 SensorNode node = e.Node.Tag as SensorNode;
329 e.Value = (node != null) &&
330 (node.Sensor.SensorType == SensorType.Temperature) &&
331 plotMenuItem.Checked;
334 private void exitClick(object sender, EventArgs e) {
338 private void timer_Tick(object sender, EventArgs e) {
339 computer.Accept(updateVisitor);
340 treeView.Invalidate();
341 plotPanel.Invalidate();
346 if (wmiProvider != null)
347 wmiProvider.Update();
350 private void SaveConfiguration() {
351 foreach (TreeColumn column in treeView.Columns)
352 settings.SetValue("treeView.Columns." + column.Header + ".Width",
355 string fileName = Path.ChangeExtension(
356 System.Windows.Forms.Application.ExecutablePath, ".config");
358 settings.Save(fileName);
359 } catch (UnauthorizedAccessException) {
360 MessageBox.Show("Access to the path '" + fileName + "' is denied. " +
361 "The current settings could not be saved.",
362 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
363 } catch (IOException) {
364 MessageBox.Show("The path '" + fileName + "' is not writeable. " +
365 "The current settings could not be saved.",
366 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
370 private void MainForm_Load(object sender, EventArgs e) {
371 Rectangle newBounds = new Rectangle {
372 X = settings.GetValue("mainForm.Location.X", Location.X),
373 Y = settings.GetValue("mainForm.Location.Y", Location.Y),
374 Width = settings.GetValue("mainForm.Width", 470),
375 Height = settings.GetValue("mainForm.Height", 640)
378 Rectangle fullWorkingArea = new Rectangle(int.MaxValue, int.MaxValue,
379 int.MinValue, int.MinValue);
381 foreach (Screen screen in Screen.AllScreens)
382 fullWorkingArea = Rectangle.Union(fullWorkingArea, screen.Bounds);
384 Rectangle intersection = Rectangle.Intersect(fullWorkingArea, newBounds);
385 if (intersection.Width < 20 || intersection.Height < 20 ||
386 !settings.Contains("mainForm.Location.X")
388 newBounds.X = (Screen.PrimaryScreen.WorkingArea.Width / 2) -
391 newBounds.Y = (Screen.PrimaryScreen.WorkingArea.Height / 2) -
392 (newBounds.Height / 2);
395 this.Bounds = newBounds;
398 private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
402 systemTray.IsMainIconEnabled = false;
403 timer.Enabled = false;
405 systemTray.Dispose();
408 private void aboutMenuItem_Click(object sender, EventArgs e) {
409 new AboutBox().ShowDialog();
412 private void treeView_Click(object sender, EventArgs e) {
414 MouseEventArgs m = e as MouseEventArgs;
415 if (m == null || m.Button != MouseButtons.Right)
418 NodeControlInfo info = treeView.GetNodeControlInfoAt(
421 treeView.SelectedNode = info.Node;
422 if (info.Node != null) {
423 SensorNode node = info.Node.Tag as SensorNode;
424 if (node != null && node.Sensor != null) {
425 treeContextMenu.MenuItems.Clear();
426 if (node.Sensor.Parameters.Length > 0) {
427 MenuItem item = new MenuItem("Parameters...");
428 item.Click += delegate(object obj, EventArgs args) {
429 ShowParameterForm(node.Sensor);
431 treeContextMenu.MenuItems.Add(item);
433 if (nodeTextBoxText.EditEnabled) {
434 MenuItem item = new MenuItem("Rename");
435 item.Click += delegate(object obj, EventArgs args) {
436 nodeTextBoxText.BeginEdit();
438 treeContextMenu.MenuItems.Add(item);
440 if (node.IsVisible) {
441 MenuItem item = new MenuItem("Hide");
442 item.Click += delegate(object obj, EventArgs args) {
443 node.IsVisible = false;
445 treeContextMenu.MenuItems.Add(item);
447 MenuItem item = new MenuItem("Unhide");
448 item.Click += delegate(object obj, EventArgs args) {
449 node.IsVisible = true;
451 treeContextMenu.MenuItems.Add(item);
453 treeContextMenu.MenuItems.Add(new MenuItem("-"));
455 MenuItem item = new MenuItem("Show in Tray");
456 item.Checked = systemTray.Contains(node.Sensor);
457 item.Click += delegate(object obj, EventArgs args) {
459 systemTray.Remove(node.Sensor);
461 systemTray.Add(node.Sensor, true);
463 treeContextMenu.MenuItems.Add(item);
465 if (gadget != null) {
466 MenuItem item = new MenuItem("Show in Gadget");
467 item.Checked = gadget.Contains(node.Sensor);
468 item.Click += delegate(object obj, EventArgs args) {
470 gadget.Remove(node.Sensor);
472 gadget.Add(node.Sensor);
475 treeContextMenu.MenuItems.Add(item);
477 if (node.Sensor.Control != null) {
478 treeContextMenu.MenuItems.Add(new MenuItem("-"));
479 IControl control = node.Sensor.Control;
480 MenuItem controlItem = new MenuItem("Control");
481 MenuItem defaultItem = new MenuItem("Default");
482 defaultItem.Checked = control.ControlMode == ControlMode.Default;
483 controlItem.MenuItems.Add(defaultItem);
484 defaultItem.Click += delegate(object obj, EventArgs args) {
485 control.SetDefault();
487 MenuItem manualItem = new MenuItem("Manual");
488 controlItem.MenuItems.Add(manualItem);
489 manualItem.Checked = control.ControlMode == ControlMode.Software;
490 for (int i = 0; i <= 100; i += 5) {
491 if (i <= control.MaxSoftwareValue &&
492 i >= control.MinSoftwareValue) {
493 MenuItem item = new MenuItem(i + " %");
494 manualItem.MenuItems.Add(item);
495 item.Checked = control.ControlMode == ControlMode.Software &&
496 Math.Round(control.SoftwareValue) == i;
497 int softwareValue = i;
498 item.Click += delegate(object obj, EventArgs args) {
499 control.SetSoftware(softwareValue);
503 treeContextMenu.MenuItems.Add(controlItem);
506 treeContextMenu.Show(treeView, new Point(m.X, m.Y));
509 HardwareNode hardwareNode = info.Node.Tag as HardwareNode;
510 if (hardwareNode != null && hardwareNode.Hardware != null) {
511 treeContextMenu.MenuItems.Clear();
513 if (nodeTextBoxText.EditEnabled) {
514 MenuItem item = new MenuItem("Rename");
515 item.Click += delegate(object obj, EventArgs args) {
516 nodeTextBoxText.BeginEdit();
518 treeContextMenu.MenuItems.Add(item);
521 treeContextMenu.Show(treeView, new Point(m.X, m.Y));
526 private void saveReportMenuItem_Click(object sender, EventArgs e) {
527 string report = computer.GetReport();
528 if (saveFileDialog.ShowDialog() == DialogResult.OK) {
529 using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) {
535 private void SysTrayHideShow() {
541 protected override void WndProc(ref Message m) {
542 const int WM_SYSCOMMAND = 0x112;
543 const int SC_MINIMIZE = 0xF020;
544 const int SC_CLOSE = 0xF060;
546 if (minimizeToTray.Value &&
547 m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) {
549 } else if(minimizeOnClose.Value &&
550 m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) {
552 * Apparently the user wants to minimize rather than close
553 * Now we still need to check if we're going to the tray or not
555 * Note: the correct way to do this would be to send out SC_MINIMIZE,
556 * but since the code here is so simple,
557 * that would just be a waste of time.
559 if (minimizeToTray.Value)
562 WindowState = FormWindowState.Minimized;
568 private void hideShowClick(object sender, EventArgs e) {
572 private void ShowParameterForm(ISensor sensor) {
573 ParameterForm form = new ParameterForm();
574 form.Parameters = sensor.Parameters;
575 form.captionLabel.Text = sensor.Name;
579 private void treeView_NodeMouseDoubleClick(object sender,
580 TreeNodeAdvMouseEventArgs e) {
581 SensorNode node = e.Node.Tag as SensorNode;
582 if (node != null && node.Sensor != null &&
583 node.Sensor.Parameters.Length > 0) {
584 ShowParameterForm(node.Sensor);
588 private void celciusMenuItem_Click(object sender, EventArgs e) {
589 celciusMenuItem.Checked = true;
590 fahrenheitMenuItem.Checked = false;
591 unitManager.TemperatureUnit = TemperatureUnit.Celcius;
594 private void fahrenheitMenuItem_Click(object sender, EventArgs e) {
595 celciusMenuItem.Checked = false;
596 fahrenheitMenuItem.Checked = true;
597 unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit;
600 private void sumbitReportMenuItem_Click(object sender, EventArgs e)
602 ReportForm form = new ReportForm();
603 form.Report = computer.GetReport();
607 private void resetMinMaxMenuItem_Click(object sender, EventArgs e) {
608 computer.Accept(new SensorVisitor(delegate(ISensor sensor) {
614 private void MainForm_MoveOrResize(object sender, EventArgs e) {
615 if (WindowState != FormWindowState.Minimized) {
616 settings.SetValue("mainForm.Location.X", Bounds.X);
617 settings.SetValue("mainForm.Location.Y", Bounds.Y);
618 settings.SetValue("mainForm.Width", Bounds.Width);
619 settings.SetValue("mainForm.Height", Bounds.Height);
623 private void resetClick(object sender, EventArgs e) {
624 // disable the fallback MainIcon during reset, otherwise icon visibility
626 systemTray.IsMainIconEnabled = false;
629 // restore the MainIcon setting
630 systemTray.IsMainIconEnabled = minimizeToTray.Value;
633 private void treeView_MouseMove(object sender, MouseEventArgs e) {
634 selectionDragging = selectionDragging &
635 (e.Button & (MouseButtons.Left | MouseButtons.Right)) > 0;
637 if (selectionDragging)
638 treeView.SelectedNode = treeView.GetNodeAt(e.Location);
641 private void treeView_MouseDown(object sender, MouseEventArgs e) {
642 selectionDragging = true;
645 private void treeView_MouseUp(object sender, MouseEventArgs e) {
646 selectionDragging = false;