GUI/SensorNotifyIcon.cs
author moel.mich
Sat, 20 Feb 2010 19:51:10 +0000
changeset 56 5cb7eb5bf628
parent 43 5b7398d061b7
child 57 142907c75be4
permissions -rw-r--r--
Improved Winbond temperature reading. Temperatures create by adding PECI Agent values (delta to TCC Activation Temperature) to a (possibly uncalibrated) TBase are not read. Direct reading temperatures from sensor report register if available. Added lower bound for temperatures on Winbond chips. Nvidia GPUs are now displayed even if they do not have any sensors.
moel@40
     1
/*
moel@40
     2
  
moel@40
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@40
     4
moel@40
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@40
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@40
     7
  the License. You may obtain a copy of the License at
moel@40
     8
 
moel@40
     9
  http://www.mozilla.org/MPL/
moel@40
    10
moel@40
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@40
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@40
    13
  for the specific language governing rights and limitations under the License.
moel@40
    14
moel@40
    15
  The Original Code is the Open Hardware Monitor code.
moel@40
    16
moel@40
    17
  The Initial Developer of the Original Code is 
moel@40
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@40
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@40
    20
  the Initial Developer. All Rights Reserved.
moel@40
    21
moel@40
    22
  Contributor(s):
moel@40
    23
moel@40
    24
  Alternatively, the contents of this file may be used under the terms of
moel@40
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@40
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@40
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@40
    28
  of those above. If you wish to allow use of your version of this file only
moel@40
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@40
    30
  use your version of this file under the terms of the MPL, indicate your
moel@40
    31
  decision by deleting the provisions above and replace them with the notice
moel@40
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@40
    33
  the provisions above, a recipient may use your version of this file under
moel@40
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@40
    35
 
moel@40
    36
*/
moel@40
    37
moel@40
    38
using System;
moel@40
    39
using System.Collections.Generic;
moel@40
    40
using System.Drawing;
moel@40
    41
using System.Drawing.Drawing2D;
moel@40
    42
using System.Drawing.Imaging;
moel@40
    43
using System.Drawing.Text;
moel@40
    44
using System.Text;
moel@40
    45
using System.Windows.Forms;
moel@40
    46
using System.Runtime.InteropServices;
moel@40
    47
using OpenHardwareMonitor.Hardware;
moel@40
    48
using OpenHardwareMonitor.Utilities;
moel@40
    49
moel@40
    50
namespace OpenHardwareMonitor.GUI {
moel@40
    51
  public class SensorNotifyIcon : IDisposable {
moel@40
    52
moel@40
    53
    private ISensor sensor;
moel@40
    54
    private NotifyIcon notifyIcon;
moel@40
    55
    private Bitmap bitmap;
moel@40
    56
    private Graphics graphics;
moel@42
    57
    private Color color;
moel@43
    58
    private Color darkColor;
moel@43
    59
    private Brush brush;
moel@43
    60
    private Brush darkBrush;
moel@43
    61
    private Pen pen;
moel@40
    62
moel@42
    63
    public SensorNotifyIcon(SensorSystemTray sensorSystemTray, ISensor sensor,
moel@42
    64
      bool balloonTip) 
moel@42
    65
    {
moel@40
    66
      this.sensor = sensor;
moel@40
    67
      this.notifyIcon = new NotifyIcon();
moel@43
    68
moel@43
    69
      Color defaultColor = Color.Black;
moel@43
    70
      if (sensor.SensorType == SensorType.Load) {
moel@43
    71
        defaultColor = Color.FromArgb(0xff, 0x70, 0x8c, 0xf1);
moel@43
    72
      }
moel@43
    73
      Color = Config.Get(sensor.Identifier + "/traycolor", defaultColor);      
moel@40
    74
      
moel@43
    75
      this.pen = new Pen(Color.FromArgb(96, Color.Black));
moel@43
    76
moel@40
    77
      ContextMenuStrip contextMenuStrip = new ContextMenuStrip();
moel@42
    78
      ToolStripMenuItem removeItem = new ToolStripMenuItem("Remove");
moel@42
    79
      removeItem.Click += delegate(object obj, EventArgs args) {
moel@42
    80
        sensorSystemTray.Remove(this.sensor);
moel@40
    81
      };
moel@42
    82
      contextMenuStrip.Items.Add(removeItem);
moel@42
    83
      ToolStripMenuItem colorItem = new ToolStripMenuItem("Change Color...");
moel@42
    84
      colorItem.Click += delegate(object obj, EventArgs args) {
moel@42
    85
        ColorDialog dialog = new ColorDialog();
moel@43
    86
        dialog.Color = Color;
moel@42
    87
        if (dialog.ShowDialog() == DialogResult.OK) {
moel@43
    88
          Color = dialog.Color;
moel@43
    89
          Config.Set(sensor.Identifier + "/traycolor", Color);
moel@42
    90
        }
moel@42
    91
      };
moel@42
    92
      contextMenuStrip.Items.Add(colorItem);
moel@40
    93
      this.notifyIcon.ContextMenuStrip = contextMenuStrip;
moel@40
    94
moel@40
    95
      this.bitmap = new Bitmap(16, 16, PixelFormat.Format32bppArgb);
moel@40
    96
      this.graphics = Graphics.FromImage(this.bitmap);
moel@40
    97
      this.graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
moel@40
    98
      this.graphics.SmoothingMode = SmoothingMode.HighQuality;
moel@40
    99
    }
moel@40
   100
moel@40
   101
    public ISensor Sensor {
moel@40
   102
      get { return sensor; }
moel@40
   103
    }
moel@40
   104
moel@42
   105
    public Color Color {
moel@42
   106
      get { return color; }
moel@43
   107
      set { 
moel@43
   108
        this.color = value;
moel@43
   109
        this.darkColor = Color.FromArgb(255,
moel@44
   110
          this.color.R / 3,
moel@44
   111
          this.color.G / 3,
moel@44
   112
          this.color.B / 3);
moel@43
   113
        Brush brush = this.brush;
moel@43
   114
        this.brush = new SolidBrush(this.color);
moel@43
   115
        if (brush != null)
moel@43
   116
          brush.Dispose();
moel@43
   117
        Brush darkBrush = this.darkBrush;
moel@43
   118
        this.darkBrush = new SolidBrush(this.darkColor);
moel@43
   119
        if (darkBrush != null)
moel@43
   120
          darkBrush.Dispose();
moel@43
   121
      }
moel@42
   122
    }
moel@42
   123
moel@40
   124
    public void Dispose() {      
moel@40
   125
      Icon icon = notifyIcon.Icon;
moel@40
   126
      notifyIcon.Icon = null;
moel@40
   127
      if (icon != null)
moel@40
   128
        icon.Dispose();      
moel@40
   129
      notifyIcon.Dispose();
moel@40
   130
      notifyIcon = null;
moel@40
   131
moel@43
   132
      if (brush != null)
moel@43
   133
        brush.Dispose();
moel@43
   134
      if (darkBrush != null)
moel@43
   135
        darkBrush.Dispose();
moel@43
   136
      pen.Dispose();
moel@40
   137
      graphics.Dispose();
moel@40
   138
      graphics = null;
moel@40
   139
      bitmap.Dispose();
moel@40
   140
      bitmap = null;
moel@40
   141
    }
moel@40
   142
moel@40
   143
    private string GetString() {
moel@40
   144
      switch (sensor.SensorType) {
moel@40
   145
        case SensorType.Voltage:
moel@40
   146
          return string.Format("{0:F11}", sensor.Value);
moel@40
   147
        case SensorType.Clock:
moel@40
   148
          return string.Format("{0:F11}", 1e-3f * sensor.Value);
moel@40
   149
        case SensorType.Load: 
moel@40
   150
          return string.Format("{0:F0}", sensor.Value < 99 ? sensor.Value : 99);
moel@40
   151
        case SensorType.Temperature: 
moel@40
   152
          return string.Format("{0:F0}", sensor.Value);
moel@40
   153
        case SensorType.Fan: 
moel@40
   154
          return string.Format("{0:F11}", 1e-3f * sensor.Value);
moel@40
   155
      }
moel@40
   156
      return "-";
moel@40
   157
    }
moel@40
   158
moel@40
   159
    private Icon CreateTransparentIcon() {
moel@40
   160
moel@40
   161
      graphics.Clear(Color.Black);
moel@40
   162
      TextRenderer.DrawText(graphics, GetString(), SystemFonts.StatusFont,
moel@40
   163
        new Point(-2, 0), Color.White, Color.Black);
moel@40
   164
moel@40
   165
      BitmapData data = bitmap.LockBits(
moel@40
   166
        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
moel@40
   167
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
moel@40
   168
moel@40
   169
      int stride = data.Stride;
moel@40
   170
      IntPtr Scan0 = data.Scan0;
moel@40
   171
moel@40
   172
      int numBytes = bitmap.Width * bitmap.Height * 4;
moel@40
   173
      byte[] bytes = new byte[numBytes];
moel@40
   174
      Marshal.Copy(Scan0, bytes, 0, numBytes);
moel@40
   175
      bitmap.UnlockBits(data);
moel@40
   176
moel@40
   177
      byte red, green, blue;
moel@40
   178
      for (int i = 0; i < bytes.Length; i += 4) {
moel@40
   179
        blue = bytes[i];
moel@40
   180
        green = bytes[i + 1];
moel@40
   181
        red = bytes[i + 2];
moel@40
   182
moel@42
   183
        bytes[i] = color.B;
moel@42
   184
        bytes[i + 1] = color.G;
moel@42
   185
        bytes[i + 2] = color.R;
moel@40
   186
        bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue);
moel@40
   187
      }
moel@40
   188
moel@40
   189
      return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb);
moel@40
   190
    }
moel@40
   191
moel@43
   192
    private Icon CreateLoadIcon() {
moel@43
   193
      graphics.Clear(Color.Transparent);
moel@43
   194
      graphics.FillRectangle(darkBrush, 0.5f, -0.5f, 14, 16);
moel@43
   195
      float y = 0.16f * (100 - sensor.Value.Value);
moel@43
   196
      graphics.FillRectangle(brush, 0.5f, -0.5f + y, 14, 16 - y);
moel@43
   197
      graphics.DrawRectangle(pen, 1, 0, 13, 15);
moel@43
   198
moel@43
   199
      BitmapData data = bitmap.LockBits(
moel@43
   200
        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
moel@43
   201
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
moel@43
   202
      byte[] bytes = new byte[bitmap.Width * bitmap.Height * 4];
moel@43
   203
      Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
moel@43
   204
      bitmap.UnlockBits(data);
moel@43
   205
moel@43
   206
      return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb);
moel@43
   207
    }
moel@43
   208
moel@40
   209
    public void Update() {
moel@40
   210
      Icon icon = notifyIcon.Icon;
moel@40
   211
moel@43
   212
      if (sensor.SensorType == SensorType.Load) {
moel@43
   213
        notifyIcon.Icon = CreateLoadIcon();
moel@40
   214
      } else {
moel@40
   215
        notifyIcon.Icon = CreateTransparentIcon();
moel@40
   216
      }
moel@40
   217
      if (icon != null) 
moel@40
   218
        icon.Dispose();
moel@40
   219
moel@40
   220
      string format = "";
moel@40
   221
      switch (sensor.SensorType) {
moel@40
   222
        case SensorType.Voltage: format = "{0}\n{1}: {2:F2} V"; break;
moel@40
   223
        case SensorType.Clock: format = "{0}\n{1}: {2:F0} MHz"; break;
moel@40
   224
        case SensorType.Load: format = "{0}\n{1}: {2:F1} %"; break;
moel@40
   225
        case SensorType.Temperature: format = "{0}\n{1}: {2:F1} °C"; break;
moel@40
   226
        case SensorType.Fan: format = "{0}\n{1}: {2:F0} RPM"; break;
moel@40
   227
      }
moel@40
   228
moel@42
   229
      notifyIcon.Text = string.Format(format, sensor.Hardware.Name, sensor.Name,
moel@42
   230
        sensor.Value);    
moel@42
   231
      notifyIcon.Visible = true;         
moel@40
   232
    }
moel@40
   233
  }
moel@40
   234
}