GUI/SensorNotifyIcon.cs
author moel.mich
Sun, 08 May 2011 22:10:13 +0000
changeset 279 6bce967ba1b5
parent 217 d93ddd6ca0af
child 282 a2793a38aac0
permissions -rw-r--r--
Fixed the bus and core clock reading on AMD family 10h model Ah CPUs. The new "Core Performance Boost" feature of these CPUs resulted in very low accuracy of the bus speed (and as a consequence also an inaccurate TSC multiplier). This fixed Issue 205.
moel@202
     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.Drawing;
moel@40
    40
using System.Drawing.Drawing2D;
moel@40
    41
using System.Drawing.Imaging;
moel@40
    42
using System.Drawing.Text;
moel@176
    43
using System.Runtime.InteropServices;
moel@40
    44
using System.Windows.Forms;
moel@40
    45
using OpenHardwareMonitor.Hardware;
moel@40
    46
using OpenHardwareMonitor.Utilities;
moel@40
    47
moel@40
    48
namespace OpenHardwareMonitor.GUI {
moel@40
    49
  public class SensorNotifyIcon : IDisposable {
moel@40
    50
moel@40
    51
    private ISensor sensor;
moel@40
    52
    private NotifyIcon notifyIcon;
moel@40
    53
    private Bitmap bitmap;
moel@40
    54
    private Graphics graphics;
moel@42
    55
    private Color color;
moel@43
    56
    private Color darkColor;
moel@43
    57
    private Brush brush;
moel@43
    58
    private Brush darkBrush;
moel@43
    59
    private Pen pen;
moel@70
    60
    private Font font;
moel@40
    61
moel@133
    62
    public SensorNotifyIcon(SystemTray sensorSystemTray, ISensor sensor,
moel@165
    63
      bool balloonTip, PersistentSettings settings) 
moel@42
    64
    {
moel@40
    65
      this.sensor = sensor;
moel@40
    66
      this.notifyIcon = new NotifyIcon();
moel@43
    67
moel@43
    68
      Color defaultColor = Color.Black;
moel@217
    69
      if (sensor.SensorType == SensorType.Load ||
moel@217
    70
          sensor.SensorType == SensorType.Control ||
moel@217
    71
          sensor.SensorType == SensorType.Level) 
moel@217
    72
      {
moel@43
    73
        defaultColor = Color.FromArgb(0xff, 0x70, 0x8c, 0xf1);
moel@43
    74
      }
moel@166
    75
      Color = settings.GetValue(new Identifier(sensor.Identifier, 
moel@109
    76
        "traycolor").ToString(), defaultColor);      
moel@40
    77
      
moel@43
    78
      this.pen = new Pen(Color.FromArgb(96, Color.Black));
moel@117
    79
      this.font = SystemFonts.MessageBoxFont;
moel@43
    80
moel@156
    81
      ContextMenu contextMenu = new ContextMenu();
moel@156
    82
      MenuItem hideShowItem = new MenuItem("Hide/Show");
moel@133
    83
      hideShowItem.Click += delegate(object obj, EventArgs args) {
moel@133
    84
        sensorSystemTray.SendHideShowCommand();
moel@133
    85
      };
moel@156
    86
      contextMenu.MenuItems.Add(hideShowItem);
moel@156
    87
      contextMenu.MenuItems.Add(new MenuItem("-"));
moel@156
    88
      MenuItem removeItem = new MenuItem("Remove Sensor");
moel@42
    89
      removeItem.Click += delegate(object obj, EventArgs args) {
moel@42
    90
        sensorSystemTray.Remove(this.sensor);
moel@40
    91
      };
moel@156
    92
      contextMenu.MenuItems.Add(removeItem);
moel@156
    93
      MenuItem colorItem = new MenuItem("Change Color...");
moel@42
    94
      colorItem.Click += delegate(object obj, EventArgs args) {
moel@42
    95
        ColorDialog dialog = new ColorDialog();
moel@43
    96
        dialog.Color = Color;
moel@42
    97
        if (dialog.ShowDialog() == DialogResult.OK) {
moel@43
    98
          Color = dialog.Color;
moel@166
    99
          settings.SetValue(new Identifier(sensor.Identifier,
moel@109
   100
            "traycolor").ToString(), Color);
moel@42
   101
        }
moel@42
   102
      };
moel@156
   103
      contextMenu.MenuItems.Add(colorItem);
moel@156
   104
      contextMenu.MenuItems.Add(new MenuItem("-"));
moel@156
   105
      MenuItem exitItem = new MenuItem("Exit");
moel@133
   106
      exitItem.Click += delegate(object obj, EventArgs args) {
moel@133
   107
        sensorSystemTray.SendExitCommand();
moel@133
   108
      };
moel@156
   109
      contextMenu.MenuItems.Add(exitItem);
moel@156
   110
      this.notifyIcon.ContextMenu = contextMenu;
moel@133
   111
      this.notifyIcon.DoubleClick += delegate(object obj, EventArgs args) {
moel@133
   112
        sensorSystemTray.SendHideShowCommand();
moel@133
   113
      };
moel@40
   114
moel@252
   115
      // get the default dpi to create an icon with the correct size
moel@252
   116
      float dpiX, dpiY;
moel@252
   117
      using (Bitmap b = new Bitmap(1, 1, PixelFormat.Format32bppArgb)) {
moel@252
   118
        dpiX = b.HorizontalResolution;
moel@252
   119
        dpiY = b.VerticalResolution;
moel@252
   120
      }
moel@252
   121
moel@252
   122
      // adjust the size of the icon to current dpi (default is 16x16 at 96 dpi) 
moel@252
   123
      int width = (int)Math.Round(16 * dpiX / 96);
moel@252
   124
      int height = (int)Math.Round(16 * dpiY / 96);
moel@252
   125
moel@252
   126
      // make sure it does never get smaller than 16x16
moel@252
   127
      width = width < 16 ? 16: width;
moel@252
   128
      height = height < 16 ? 16: height;
moel@252
   129
moel@252
   130
      this.bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);      
moel@40
   131
      this.graphics = Graphics.FromImage(this.bitmap);
moel@117
   132
moel@117
   133
      if (Environment.OSVersion.Version.Major > 5) {
moel@117
   134
        this.graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
moel@117
   135
        this.graphics.SmoothingMode = SmoothingMode.HighQuality;
moel@117
   136
      }
moel@40
   137
    }
moel@40
   138
moel@40
   139
    public ISensor Sensor {
moel@40
   140
      get { return sensor; }
moel@40
   141
    }
moel@40
   142
moel@42
   143
    public Color Color {
moel@42
   144
      get { return color; }
moel@43
   145
      set { 
moel@43
   146
        this.color = value;
moel@43
   147
        this.darkColor = Color.FromArgb(255,
moel@44
   148
          this.color.R / 3,
moel@44
   149
          this.color.G / 3,
moel@44
   150
          this.color.B / 3);
moel@43
   151
        Brush brush = this.brush;
moel@43
   152
        this.brush = new SolidBrush(this.color);
moel@43
   153
        if (brush != null)
moel@43
   154
          brush.Dispose();
moel@43
   155
        Brush darkBrush = this.darkBrush;
moel@43
   156
        this.darkBrush = new SolidBrush(this.darkColor);
moel@43
   157
        if (darkBrush != null)
moel@43
   158
          darkBrush.Dispose();
moel@43
   159
      }
moel@42
   160
    }
moel@42
   161
moel@40
   162
    public void Dispose() {      
moel@40
   163
      Icon icon = notifyIcon.Icon;
moel@40
   164
      notifyIcon.Icon = null;
moel@40
   165
      if (icon != null)
moel@40
   166
        icon.Dispose();      
moel@40
   167
      notifyIcon.Dispose();
moel@40
   168
moel@43
   169
      if (brush != null)
moel@43
   170
        brush.Dispose();
moel@43
   171
      if (darkBrush != null)
moel@43
   172
        darkBrush.Dispose();
moel@43
   173
      pen.Dispose();
moel@85
   174
      graphics.Dispose();      
moel@85
   175
      bitmap.Dispose();      
moel@40
   176
    }
moel@40
   177
moel@40
   178
    private string GetString() {
moel@40
   179
      switch (sensor.SensorType) {
moel@40
   180
        case SensorType.Voltage:
moel@40
   181
          return string.Format("{0:F11}", sensor.Value);
moel@40
   182
        case SensorType.Clock:
moel@40
   183
          return string.Format("{0:F11}", 1e-3f * sensor.Value);
moel@40
   184
        case SensorType.Load: 
moel@118
   185
          return string.Format("{0:F0}", sensor.Value);
moel@40
   186
        case SensorType.Temperature: 
moel@40
   187
          return string.Format("{0:F0}", sensor.Value);
moel@40
   188
        case SensorType.Fan: 
moel@40
   189
          return string.Format("{0:F11}", 1e-3f * sensor.Value);
moel@57
   190
        case SensorType.Flow:
moel@57
   191
          return string.Format("{0:F11}", 1e-3f * sensor.Value);
moel@118
   192
        case SensorType.Control:
moel@118
   193
          return string.Format("{0:F0}", sensor.Value);
moel@217
   194
        case SensorType.Level:
moel@217
   195
          return string.Format("{0:F0}", sensor.Value);
moel@40
   196
      }
moel@40
   197
      return "-";
moel@40
   198
    }
moel@40
   199
moel@40
   200
    private Icon CreateTransparentIcon() {
moel@40
   201
moel@40
   202
      graphics.Clear(Color.Black);
moel@70
   203
      TextRenderer.DrawText(graphics, GetString(), font,
moel@117
   204
        new Point(-2, 0), Color.White, Color.Black);        
moel@40
   205
moel@40
   206
      BitmapData data = bitmap.LockBits(
moel@40
   207
        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
moel@40
   208
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
moel@40
   209
moel@40
   210
      IntPtr Scan0 = data.Scan0;
moel@40
   211
moel@40
   212
      int numBytes = bitmap.Width * bitmap.Height * 4;
moel@40
   213
      byte[] bytes = new byte[numBytes];
moel@40
   214
      Marshal.Copy(Scan0, bytes, 0, numBytes);
moel@40
   215
      bitmap.UnlockBits(data);
moel@40
   216
moel@40
   217
      byte red, green, blue;
moel@40
   218
      for (int i = 0; i < bytes.Length; i += 4) {
moel@40
   219
        blue = bytes[i];
moel@40
   220
        green = bytes[i + 1];
moel@40
   221
        red = bytes[i + 2];
moel@40
   222
moel@42
   223
        bytes[i] = color.B;
moel@42
   224
        bytes[i + 1] = color.G;
moel@42
   225
        bytes[i + 2] = color.R;
moel@40
   226
        bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue);
moel@40
   227
      }
moel@40
   228
moel@252
   229
      return IconFactory.Create(bytes, bitmap.Width, bitmap.Height, 
moel@252
   230
        PixelFormat.Format32bppArgb);
moel@40
   231
    }
moel@40
   232
moel@217
   233
    private Icon CreatePercentageIcon() {      
moel@86
   234
      try {
moel@86
   235
        graphics.Clear(Color.Transparent);
moel@86
   236
      } catch (ArgumentException) {
moel@86
   237
        graphics.Clear(Color.Black);
moel@86
   238
      }
moel@252
   239
      graphics.FillRectangle(darkBrush, 0.5f, -0.5f, bitmap.Width - 2, bitmap.Height);
moel@43
   240
      float y = 0.16f * (100 - sensor.Value.Value);
moel@252
   241
      graphics.FillRectangle(brush, 0.5f, -0.5f + y, bitmap.Width - 2, bitmap.Height - y);
moel@252
   242
      graphics.DrawRectangle(pen, 1, 0, bitmap.Width - 3, bitmap.Height - 1);
moel@43
   243
moel@43
   244
      BitmapData data = bitmap.LockBits(
moel@43
   245
        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
moel@43
   246
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
moel@43
   247
      byte[] bytes = new byte[bitmap.Width * bitmap.Height * 4];
moel@43
   248
      Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
moel@43
   249
      bitmap.UnlockBits(data);
moel@43
   250
moel@252
   251
      return IconFactory.Create(bytes, bitmap.Width, bitmap.Height, 
moel@252
   252
        PixelFormat.Format32bppArgb);
moel@43
   253
    }
moel@43
   254
moel@40
   255
    public void Update() {
moel@40
   256
      Icon icon = notifyIcon.Icon;
moel@40
   257
moel@217
   258
      switch (sensor.SensorType) {
moel@217
   259
        case SensorType.Load:
moel@217
   260
        case SensorType.Control:
moel@217
   261
        case SensorType.Level:
moel@217
   262
          notifyIcon.Icon = CreatePercentageIcon();
moel@217
   263
          break;
moel@217
   264
        default:
moel@217
   265
          notifyIcon.Icon = CreateTransparentIcon();
moel@217
   266
          break;
moel@40
   267
      }
moel@217
   268
moel@40
   269
      if (icon != null) 
moel@40
   270
        icon.Dispose();
moel@40
   271
moel@40
   272
      string format = "";
moel@40
   273
      switch (sensor.SensorType) {
moel@116
   274
        case SensorType.Voltage: format = "\n{0}: {1:F2} V"; break;
moel@116
   275
        case SensorType.Clock: format = "\n{0}: {1:F0} MHz"; break;
moel@116
   276
        case SensorType.Load: format = "\n{0}: {1:F1} %"; break;
moel@116
   277
        case SensorType.Temperature: format = "\n{0}: {1:F1} °C"; break;
moel@116
   278
        case SensorType.Fan: format = "\n{0}: {1:F0} RPM"; break;
moel@116
   279
        case SensorType.Flow: format = "\n{0}: {1:F0} L/h"; break;
moel@118
   280
        case SensorType.Control: format = "\n{0}: {1:F1} %"; break;
moel@217
   281
        case SensorType.Level: format = "\n{0}: {1:F1} %"; break;
moel@40
   282
      }
moel@116
   283
      string formattedValue = string.Format(format, sensor.Name, sensor.Value);
moel@116
   284
      string hardwareName = sensor.Hardware.Name;
moel@116
   285
      hardwareName = hardwareName.Substring(0, 
moel@116
   286
        Math.Min(63 - formattedValue.Length, hardwareName.Length));
moel@116
   287
      string text = hardwareName + formattedValue;
moel@116
   288
      if (text.Length > 63)
moel@116
   289
        text = null;
moel@40
   290
moel@116
   291
      notifyIcon.Text = text;
moel@42
   292
      notifyIcon.Visible = true;         
moel@40
   293
    }
moel@40
   294
  }
moel@40
   295
}