GUI/SensorNotifyIcon.cs
author moel.mich
Tue, 09 Mar 2010 22:27:10 +0000
changeset 79 9cdbe1d8d12a
parent 70 dc69dc4d7512
child 85 ec4ccaa1210d
permissions -rw-r--r--
Changed the CPU clock calculation. If no invariant TSC is available, then the max CPU clock is estimated at startup under load, otherwise an average over one second is used.
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@70
    62
    private Font font;
moel@40
    63
moel@42
    64
    public SensorNotifyIcon(SensorSystemTray sensorSystemTray, ISensor sensor,
moel@42
    65
      bool balloonTip) 
moel@42
    66
    {
moel@40
    67
      this.sensor = sensor;
moel@40
    68
      this.notifyIcon = new NotifyIcon();
moel@43
    69
moel@43
    70
      Color defaultColor = Color.Black;
moel@43
    71
      if (sensor.SensorType == SensorType.Load) {
moel@43
    72
        defaultColor = Color.FromArgb(0xff, 0x70, 0x8c, 0xf1);
moel@43
    73
      }
moel@43
    74
      Color = Config.Get(sensor.Identifier + "/traycolor", defaultColor);      
moel@40
    75
      
moel@43
    76
      this.pen = new Pen(Color.FromArgb(96, Color.Black));
moel@72
    77
      this.font = new Font(SystemFonts.MessageBoxFont.FontFamily, 9);
moel@43
    78
moel@40
    79
      ContextMenuStrip contextMenuStrip = new ContextMenuStrip();
moel@42
    80
      ToolStripMenuItem removeItem = new ToolStripMenuItem("Remove");
moel@42
    81
      removeItem.Click += delegate(object obj, EventArgs args) {
moel@42
    82
        sensorSystemTray.Remove(this.sensor);
moel@40
    83
      };
moel@42
    84
      contextMenuStrip.Items.Add(removeItem);
moel@42
    85
      ToolStripMenuItem colorItem = new ToolStripMenuItem("Change Color...");
moel@42
    86
      colorItem.Click += delegate(object obj, EventArgs args) {
moel@42
    87
        ColorDialog dialog = new ColorDialog();
moel@43
    88
        dialog.Color = Color;
moel@42
    89
        if (dialog.ShowDialog() == DialogResult.OK) {
moel@43
    90
          Color = dialog.Color;
moel@43
    91
          Config.Set(sensor.Identifier + "/traycolor", Color);
moel@42
    92
        }
moel@42
    93
      };
moel@42
    94
      contextMenuStrip.Items.Add(colorItem);
moel@40
    95
      this.notifyIcon.ContextMenuStrip = contextMenuStrip;
moel@40
    96
moel@40
    97
      this.bitmap = new Bitmap(16, 16, PixelFormat.Format32bppArgb);
moel@40
    98
      this.graphics = Graphics.FromImage(this.bitmap);
moel@40
    99
      this.graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
moel@40
   100
      this.graphics.SmoothingMode = SmoothingMode.HighQuality;
moel@40
   101
    }
moel@40
   102
moel@40
   103
    public ISensor Sensor {
moel@40
   104
      get { return sensor; }
moel@40
   105
    }
moel@40
   106
moel@42
   107
    public Color Color {
moel@42
   108
      get { return color; }
moel@43
   109
      set { 
moel@43
   110
        this.color = value;
moel@43
   111
        this.darkColor = Color.FromArgb(255,
moel@44
   112
          this.color.R / 3,
moel@44
   113
          this.color.G / 3,
moel@44
   114
          this.color.B / 3);
moel@43
   115
        Brush brush = this.brush;
moel@43
   116
        this.brush = new SolidBrush(this.color);
moel@43
   117
        if (brush != null)
moel@43
   118
          brush.Dispose();
moel@43
   119
        Brush darkBrush = this.darkBrush;
moel@43
   120
        this.darkBrush = new SolidBrush(this.darkColor);
moel@43
   121
        if (darkBrush != null)
moel@43
   122
          darkBrush.Dispose();
moel@43
   123
      }
moel@42
   124
    }
moel@42
   125
moel@40
   126
    public void Dispose() {      
moel@40
   127
      Icon icon = notifyIcon.Icon;
moel@40
   128
      notifyIcon.Icon = null;
moel@40
   129
      if (icon != null)
moel@40
   130
        icon.Dispose();      
moel@40
   131
      notifyIcon.Dispose();
moel@40
   132
      notifyIcon = null;
moel@40
   133
moel@43
   134
      if (brush != null)
moel@43
   135
        brush.Dispose();
moel@43
   136
      if (darkBrush != null)
moel@43
   137
        darkBrush.Dispose();
moel@43
   138
      pen.Dispose();
moel@70
   139
      font.Dispose();
moel@40
   140
      graphics.Dispose();
moel@40
   141
      graphics = null;
moel@40
   142
      bitmap.Dispose();
moel@40
   143
      bitmap = null;
moel@40
   144
    }
moel@40
   145
moel@40
   146
    private string GetString() {
moel@40
   147
      switch (sensor.SensorType) {
moel@40
   148
        case SensorType.Voltage:
moel@40
   149
          return string.Format("{0:F11}", sensor.Value);
moel@40
   150
        case SensorType.Clock:
moel@40
   151
          return string.Format("{0:F11}", 1e-3f * sensor.Value);
moel@40
   152
        case SensorType.Load: 
moel@40
   153
          return string.Format("{0:F0}", sensor.Value < 99 ? sensor.Value : 99);
moel@40
   154
        case SensorType.Temperature: 
moel@40
   155
          return string.Format("{0:F0}", sensor.Value);
moel@40
   156
        case SensorType.Fan: 
moel@40
   157
          return string.Format("{0:F11}", 1e-3f * sensor.Value);
moel@57
   158
        case SensorType.Flow:
moel@57
   159
          return string.Format("{0:F11}", 1e-3f * sensor.Value);
moel@40
   160
      }
moel@40
   161
      return "-";
moel@40
   162
    }
moel@40
   163
moel@40
   164
    private Icon CreateTransparentIcon() {
moel@40
   165
moel@40
   166
      graphics.Clear(Color.Black);
moel@70
   167
      TextRenderer.DrawText(graphics, GetString(), font,
moel@40
   168
        new Point(-2, 0), Color.White, Color.Black);
moel@40
   169
moel@40
   170
      BitmapData data = bitmap.LockBits(
moel@40
   171
        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
moel@40
   172
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
moel@40
   173
moel@40
   174
      int stride = data.Stride;
moel@40
   175
      IntPtr Scan0 = data.Scan0;
moel@40
   176
moel@40
   177
      int numBytes = bitmap.Width * bitmap.Height * 4;
moel@40
   178
      byte[] bytes = new byte[numBytes];
moel@40
   179
      Marshal.Copy(Scan0, bytes, 0, numBytes);
moel@40
   180
      bitmap.UnlockBits(data);
moel@40
   181
moel@40
   182
      byte red, green, blue;
moel@40
   183
      for (int i = 0; i < bytes.Length; i += 4) {
moel@40
   184
        blue = bytes[i];
moel@40
   185
        green = bytes[i + 1];
moel@40
   186
        red = bytes[i + 2];
moel@40
   187
moel@42
   188
        bytes[i] = color.B;
moel@42
   189
        bytes[i + 1] = color.G;
moel@42
   190
        bytes[i + 2] = color.R;
moel@40
   191
        bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue);
moel@40
   192
      }
moel@40
   193
moel@40
   194
      return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb);
moel@40
   195
    }
moel@40
   196
moel@43
   197
    private Icon CreateLoadIcon() {
moel@43
   198
      graphics.Clear(Color.Transparent);
moel@43
   199
      graphics.FillRectangle(darkBrush, 0.5f, -0.5f, 14, 16);
moel@43
   200
      float y = 0.16f * (100 - sensor.Value.Value);
moel@43
   201
      graphics.FillRectangle(brush, 0.5f, -0.5f + y, 14, 16 - y);
moel@43
   202
      graphics.DrawRectangle(pen, 1, 0, 13, 15);
moel@43
   203
moel@43
   204
      BitmapData data = bitmap.LockBits(
moel@43
   205
        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
moel@43
   206
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
moel@43
   207
      byte[] bytes = new byte[bitmap.Width * bitmap.Height * 4];
moel@43
   208
      Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
moel@43
   209
      bitmap.UnlockBits(data);
moel@43
   210
moel@43
   211
      return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb);
moel@43
   212
    }
moel@43
   213
moel@40
   214
    public void Update() {
moel@40
   215
      Icon icon = notifyIcon.Icon;
moel@40
   216
moel@43
   217
      if (sensor.SensorType == SensorType.Load) {
moel@43
   218
        notifyIcon.Icon = CreateLoadIcon();
moel@40
   219
      } else {
moel@40
   220
        notifyIcon.Icon = CreateTransparentIcon();
moel@40
   221
      }
moel@40
   222
      if (icon != null) 
moel@40
   223
        icon.Dispose();
moel@40
   224
moel@40
   225
      string format = "";
moel@40
   226
      switch (sensor.SensorType) {
moel@40
   227
        case SensorType.Voltage: format = "{0}\n{1}: {2:F2} V"; break;
moel@40
   228
        case SensorType.Clock: format = "{0}\n{1}: {2:F0} MHz"; break;
moel@40
   229
        case SensorType.Load: format = "{0}\n{1}: {2:F1} %"; break;
moel@40
   230
        case SensorType.Temperature: format = "{0}\n{1}: {2:F1} °C"; break;
moel@40
   231
        case SensorType.Fan: format = "{0}\n{1}: {2:F0} RPM"; break;
moel@57
   232
        case SensorType.Flow: format = "{0}\n{1}: {2:F0} L/h"; break;
moel@40
   233
      }
moel@40
   234
moel@42
   235
      notifyIcon.Text = string.Format(format, sensor.Hardware.Name, sensor.Name,
moel@42
   236
        sensor.Value);    
moel@42
   237
      notifyIcon.Visible = true;         
moel@40
   238
    }
moel@40
   239
  }
moel@40
   240
}