Fixed Issue 91.
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-2010
20 the Initial Developer. All Rights Reserved.
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;
41 using System.Drawing.Drawing2D;
42 using System.Drawing.Imaging;
43 using System.Drawing.Text;
45 using System.Windows.Forms;
46 using System.Runtime.InteropServices;
47 using OpenHardwareMonitor.Hardware;
48 using OpenHardwareMonitor.Utilities;
50 namespace OpenHardwareMonitor.GUI {
51 public class SensorNotifyIcon : IDisposable {
53 private ISensor sensor;
54 private NotifyIcon notifyIcon;
55 private Bitmap bitmap;
56 private Graphics graphics;
58 private Color darkColor;
60 private Brush darkBrush;
64 public SensorNotifyIcon(SystemTray sensorSystemTray, ISensor sensor,
68 this.notifyIcon = new NotifyIcon();
70 Color defaultColor = Color.Black;
71 if (sensor.SensorType == SensorType.Load) {
72 defaultColor = Color.FromArgb(0xff, 0x70, 0x8c, 0xf1);
74 Color = Config.Get(new Identifier(sensor.Identifier,
75 "traycolor").ToString(), defaultColor);
77 this.pen = new Pen(Color.FromArgb(96, Color.Black));
78 this.font = SystemFonts.MessageBoxFont;
80 ContextMenuStrip contextMenuStrip = new ContextMenuStrip();
81 ToolStripMenuItem hideShowItem = new ToolStripMenuItem("Hide/Show");
82 hideShowItem.Click += delegate(object obj, EventArgs args) {
83 sensorSystemTray.SendHideShowCommand();
85 contextMenuStrip.Items.Add(hideShowItem);
86 contextMenuStrip.Items.Add(new ToolStripSeparator());
87 ToolStripMenuItem removeItem = new ToolStripMenuItem("Remove Sensor");
88 removeItem.Click += delegate(object obj, EventArgs args) {
89 sensorSystemTray.Remove(this.sensor);
91 contextMenuStrip.Items.Add(removeItem);
92 ToolStripMenuItem colorItem = new ToolStripMenuItem("Change Color...");
93 colorItem.Click += delegate(object obj, EventArgs args) {
94 ColorDialog dialog = new ColorDialog();
96 if (dialog.ShowDialog() == DialogResult.OK) {
98 Config.Set(new Identifier(sensor.Identifier,
99 "traycolor").ToString(), Color);
102 contextMenuStrip.Items.Add(colorItem);
103 contextMenuStrip.Items.Add(new ToolStripSeparator());
104 ToolStripMenuItem exitItem = new ToolStripMenuItem("Exit");
105 exitItem.Click += delegate(object obj, EventArgs args) {
106 sensorSystemTray.SendExitCommand();
108 contextMenuStrip.Items.Add(exitItem);
109 this.notifyIcon.ContextMenuStrip = contextMenuStrip;
110 this.notifyIcon.DoubleClick += delegate(object obj, EventArgs args) {
111 sensorSystemTray.SendHideShowCommand();
114 this.bitmap = new Bitmap(16, 16, PixelFormat.Format32bppArgb);
115 this.graphics = Graphics.FromImage(this.bitmap);
117 if (Environment.OSVersion.Version.Major > 5) {
118 this.graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
119 this.graphics.SmoothingMode = SmoothingMode.HighQuality;
123 public ISensor Sensor {
124 get { return sensor; }
128 get { return color; }
131 this.darkColor = Color.FromArgb(255,
135 Brush brush = this.brush;
136 this.brush = new SolidBrush(this.color);
139 Brush darkBrush = this.darkBrush;
140 this.darkBrush = new SolidBrush(this.darkColor);
141 if (darkBrush != null)
146 public void Dispose() {
147 Icon icon = notifyIcon.Icon;
148 notifyIcon.Icon = null;
151 notifyIcon.Dispose();
155 if (darkBrush != null)
162 private string GetString() {
163 switch (sensor.SensorType) {
164 case SensorType.Voltage:
165 return string.Format("{0:F11}", sensor.Value);
166 case SensorType.Clock:
167 return string.Format("{0:F11}", 1e-3f * sensor.Value);
168 case SensorType.Load:
169 return string.Format("{0:F0}", sensor.Value);
170 case SensorType.Temperature:
171 return string.Format("{0:F0}", sensor.Value);
173 return string.Format("{0:F11}", 1e-3f * sensor.Value);
174 case SensorType.Flow:
175 return string.Format("{0:F11}", 1e-3f * sensor.Value);
176 case SensorType.Control:
177 return string.Format("{0:F0}", sensor.Value);
182 private Icon CreateTransparentIcon() {
184 graphics.Clear(Color.Black);
185 TextRenderer.DrawText(graphics, GetString(), font,
186 new Point(-2, 0), Color.White, Color.Black);
188 BitmapData data = bitmap.LockBits(
189 new Rectangle(0, 0, bitmap.Width, bitmap.Height),
190 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
192 int stride = data.Stride;
193 IntPtr Scan0 = data.Scan0;
195 int numBytes = bitmap.Width * bitmap.Height * 4;
196 byte[] bytes = new byte[numBytes];
197 Marshal.Copy(Scan0, bytes, 0, numBytes);
198 bitmap.UnlockBits(data);
200 byte red, green, blue;
201 for (int i = 0; i < bytes.Length; i += 4) {
203 green = bytes[i + 1];
207 bytes[i + 1] = color.G;
208 bytes[i + 2] = color.R;
209 bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue);
212 return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb);
215 private Icon CreateLoadIcon() {
217 graphics.Clear(Color.Transparent);
218 } catch (ArgumentException) {
219 graphics.Clear(Color.Black);
221 graphics.FillRectangle(darkBrush, 0.5f, -0.5f, 14, 16);
222 float y = 0.16f * (100 - sensor.Value.Value);
223 graphics.FillRectangle(brush, 0.5f, -0.5f + y, 14, 16 - y);
224 graphics.DrawRectangle(pen, 1, 0, 13, 15);
226 BitmapData data = bitmap.LockBits(
227 new Rectangle(0, 0, bitmap.Width, bitmap.Height),
228 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
229 byte[] bytes = new byte[bitmap.Width * bitmap.Height * 4];
230 Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
231 bitmap.UnlockBits(data);
233 return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb);
236 public void Update() {
237 Icon icon = notifyIcon.Icon;
239 if (sensor.SensorType == SensorType.Load) {
240 notifyIcon.Icon = CreateLoadIcon();
242 notifyIcon.Icon = CreateTransparentIcon();
248 switch (sensor.SensorType) {
249 case SensorType.Voltage: format = "\n{0}: {1:F2} V"; break;
250 case SensorType.Clock: format = "\n{0}: {1:F0} MHz"; break;
251 case SensorType.Load: format = "\n{0}: {1:F1} %"; break;
252 case SensorType.Temperature: format = "\n{0}: {1:F1} °C"; break;
253 case SensorType.Fan: format = "\n{0}: {1:F0} RPM"; break;
254 case SensorType.Flow: format = "\n{0}: {1:F0} L/h"; break;
255 case SensorType.Control: format = "\n{0}: {1:F1} %"; break;
257 string formattedValue = string.Format(format, sensor.Name, sensor.Value);
258 string hardwareName = sensor.Hardware.Name;
259 hardwareName = hardwareName.Substring(0,
260 Math.Min(63 - formattedValue.Length, hardwareName.Length));
261 string text = hardwareName + formattedValue;
262 if (text.Length > 63)
265 notifyIcon.Text = text;
266 notifyIcon.Visible = true;