# HG changeset patch # User moel.mich # Date 1265935016 0 # Node ID 2392f7402fb6d355f3d97efa4adaa92414567fc4 # Parent 654696eeebe8b0c2ab2c59f3d2044bccf91a76a9 First system tray sensor monitor support. diff -r 654696eeebe8 -r 2392f7402fb6 GUI/MainForm.Designer.cs --- a/GUI/MainForm.Designer.cs Thu Feb 11 13:22:17 2010 +0000 +++ b/GUI/MainForm.Designer.cs Fri Feb 12 00:36:56 2010 +0000 @@ -102,11 +102,11 @@ this.timer = new System.Windows.Forms.Timer(this.components); this.splitContainer = new System.Windows.Forms.SplitContainer(); this.plotPanel = new OpenHardwareMonitor.GUI.PlotPanel(); - this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); this.notifyContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.restoreToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator(); this.exitToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.sensorContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.columnsContextMenuStrip.SuspendLayout(); this.menuStrip.SuspendLayout(); this.splitContainer.Panel1.SuspendLayout(); @@ -490,13 +490,6 @@ this.plotPanel.Size = new System.Drawing.Size(478, 198); this.plotPanel.TabIndex = 0; // - // notifyIcon - // - this.notifyIcon.ContextMenuStrip = this.notifyContextMenuStrip; - this.notifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon.Icon"))); - this.notifyIcon.Text = "Open Hardware Monitor"; - this.notifyIcon.DoubleClick += new System.EventHandler(this.restoreClick); - // // notifyContextMenuStrip // this.notifyContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -526,6 +519,11 @@ this.exitToolStripMenuItem1.Text = "Exit"; this.exitToolStripMenuItem1.Click += new System.EventHandler(this.exitToolStripMenuItem_Click); // + // sensorContextMenuStrip + // + this.sensorContextMenuStrip.Name = "sensorContextMenuStrip"; + this.sensorContextMenuStrip.Size = new System.Drawing.Size(61, 4); + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); @@ -592,13 +590,13 @@ private System.Windows.Forms.ToolStripMenuItem voltMenuItem; private System.Windows.Forms.ToolStripMenuItem hddMenuItem; private System.Windows.Forms.ToolStripMenuItem loadMenuItem; - private System.Windows.Forms.NotifyIcon notifyIcon; private System.Windows.Forms.ContextMenuStrip notifyContextMenuStrip; private System.Windows.Forms.ToolStripMenuItem restoreToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2; private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem1; private System.Windows.Forms.ToolStripMenuItem minTrayMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem3; + private System.Windows.Forms.ContextMenuStrip sensorContextMenuStrip; } } diff -r 654696eeebe8 -r 2392f7402fb6 GUI/MainForm.cs --- a/GUI/MainForm.cs Thu Feb 11 13:22:17 2010 +0000 +++ b/GUI/MainForm.cs Fri Feb 12 00:36:56 2010 +0000 @@ -56,6 +56,8 @@ private IDictionary sensorPlotColors = new Dictionary(); private Color[] plotColorPalette; + private SensorSystemTray sensorSystemTray; + private NotifyIcon notifyIcon; public MainForm() { InitializeComponent(); @@ -98,6 +100,14 @@ treeModel.Nodes.Add(root); treeView.Model = treeModel; + + notifyIcon = new NotifyIcon(); + notifyIcon.ContextMenuStrip = this.notifyContextMenuStrip; + notifyIcon.Icon = EmbeddedResources.GetIcon("smallicon.ico"); + notifyIcon.Text = "Open Hardware Monitor"; + notifyIcon.DoubleClick += new EventHandler(this.restoreClick); + + sensorSystemTray = new SensorSystemTray(computer); computer.HardwareAdded += new HardwareEventHandler(HardwareAdded); computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved); @@ -218,6 +228,7 @@ treeView.Invalidate(); plotPanel.Invalidate(); + sensorSystemTray.Redraw(); } private void MainForm_FormClosed(object sender, FormClosedEventArgs e) { @@ -242,6 +253,9 @@ Config.Set("mainForm.Width", Width); Config.Set("mainForm.Height", Height); } + + sensorSystemTray.Dispose(); + notifyIcon.Dispose(); computer.Close(); } @@ -287,7 +301,27 @@ NodeControlInfo info = treeView.GetNodeControlInfoAt(new Point(m.X, m.Y)); if (info.Control == null) { columnsContextMenuStrip.Show(treeView, m.X, m.Y); - } + } else { + SensorNode node = info.Node.Tag as SensorNode; + if (node != null && node.Sensor != null) { + + sensorContextMenuStrip.Items.Clear(); + if (sensorSystemTray.Contains(node.Sensor)) { + ToolStripMenuItem item = new ToolStripMenuItem("Remove From Tray"); + item.Click += delegate(object obj, EventArgs args) { + sensorSystemTray.Remove(node.Sensor); + }; + sensorContextMenuStrip.Items.Add(item); + } else { + ToolStripMenuItem item = new ToolStripMenuItem("Add To Tray"); + item.Click += delegate(object obj, EventArgs args) { + sensorSystemTray.Add(node.Sensor); + }; + sensorContextMenuStrip.Items.Add(item); + } + sensorContextMenuStrip.Show(treeView, m.X, m.Y); + } + } } private void saveReportToolStripMenuItem_Click(object sender, EventArgs e) { @@ -338,5 +372,17 @@ ToggleSysTray(); } + private void removeToolStripMenuItem_Click(object sender, EventArgs e) { + ToolStripMenuItem item = sender as ToolStripMenuItem; + if (item == null) + return; + + ISensor sensor = item.Owner.Tag as ISensor; + if (sensor == null) + return; + + sensorSystemTray.Remove(sensor); + } + } } diff -r 654696eeebe8 -r 2392f7402fb6 GUI/MainForm.resx --- a/GUI/MainForm.resx Thu Feb 11 13:22:17 2010 +0000 +++ b/GUI/MainForm.resx Fri Feb 12 00:36:56 2010 +0000 @@ -126,40 +126,16 @@ 124, 15 - - 401, 15 + + 399, 15 - - 507, 15 + + 571, 15 - - - - AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AABFPDspLg4HSCMUElEcHR1PGRoaTxYWFk8UFBRPEhISTw8QD08NCgpPCgUETwgEA08HAwFPBwEATwYE - BFEFBQU8S1VW/y9tef83V1z/PTs7/zg3N/8zNDP/Ly8v/yoqKv8mJSX/IiYn/xsnKf8YICP/FB4g/xIe - IP8OEhP/BgQEUUFka/8Rl7T/MlJZ/zQyMf8uLi3/Kioq/ykoKP8nJyf/JSQj/yIpKv8bOD3/Gjg+/xs6 - Qf8aOD3/Ehob/wcDA09NWlz+OlJY/j83NP5HR0f+TE1N/kNDQ/48PDz+Nzc3/i8vL/4oKCj+JSgp/iIn - KP4cIiP+HB8g/xQTFP8GBwZPV1VV/kY/Pv5JSUn+oqKi/q6vrv6fn5/+mJiY/o+Pj/6EhIT+enp6/nVy - cv5jYGD+Ih8e/hsZGv8VFRX/BwcHT1taWv5FRUT+WFhY/q6urv6+vr7+sLCv/qmpqf6goKD+lJSU/omJ - if6BgYH+cXFx/iQkJP4bGxv/FhYW/wcHB09eXl7+SEhI/lpaWv61tbX+xsbG/ra2tv6srKv+oaGi/paW - lv6MjIz+hISE/nJycv4kJCT+HBwc/xgYGP8HBwdPY2Nj/k1MTP5eXl7+wMDA/tHR0f6+vr7+r6+v/qOj - pP6ZmJn+kZOT/oqLiv53eHf+JSUl/h0dHf8ZGRn/BwcHT2dnZ/5QUFD+YmJi/srKyv7c3Nz+x8bH/rW0 - tf6pqan+n5+f/piYmP6Oj4/+e3t8/iUlJv4eHh7/Ghoa/wgICE9ra2v+U1NT/mRkZP7S0tL+4+Xj/szM - zP68vLz+sLCw/qampv6bm5v+k5GR/n9/f/4oKCj+Hx8e/xwcHP8JCQpPbm5u/lZVVv5mZWb+19bX/ujo - 6P7T0tP+x8fH/rq6uv6rq6v+nZ6e/pSUlP6BgYD+LCws/h8eHv8eHRz/CwsLT29vb/5WVlb+Z2do/uHh - 4f7y8fL+2dnZ/s3Nzf7AwMD+sLKy/qSjpP6ZmZn+hoaG/jAwMP4fIB//Hh8f/w0LDU9vb2/+WFhY/lla - Wv7BwcH+1dXV/sDAv/61tbT+qamp/pubm/6Oj47+hYWF/nFxcf4uKir+ICwu/x4qLf8OCQdPb29w/lpZ - Wv5SUlH+VVVV/mBgYP5bW1r+VVVT/k5OTv5HR0f+QUFB/js7Ov4wLy/+KCgo/iM5Pf8fLS//EAkIUW5u - bv5VVVX+UlJS/ktLS/5ERET+QUFB/j09Pf45OTn+NTU1/jMyMv4vLy7+LCko/icuL/4fQ0z/Ii4x/xMN - Ckh6e3r+ampq/mVlZf5hYWL+XFxc/lhYWP5TUlP+TU1N/kdGR/5CQkL+PTw8/jc1Nf4wMTH+KjEy/yYo - Kf8eHBwp//8AAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAB - AAAAAQAAAAEAAA== - - 55 + AAABAAMAEBAAAAEAIABoBAAANgAAACAgAAABACAAqBAAAJ4EAAAwMAAAAQAgAKglAABGFQAAKAAAABAA diff -r 654696eeebe8 -r 2392f7402fb6 GUI/SensorNotifyIcon.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GUI/SensorNotifyIcon.cs Fri Feb 12 00:36:56 2010 +0000 @@ -0,0 +1,192 @@ +/* + + Version: MPL 1.1/GPL 2.0/LGPL 2.1 + + The contents of this file are subject to the Mozilla Public License Version + 1.1 (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + The Original Code is the Open Hardware Monitor code. + + The Initial Developer of the Original Code is + Michael Möller . + Portions created by the Initial Developer are Copyright (C) 2009-2010 + the Initial Developer. All Rights Reserved. + + Contributor(s): + + Alternatively, the contents of this file may be used under the terms of + either the GNU General Public License Version 2 or later (the "GPL"), or + the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + in which case the provisions of the GPL or the LGPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of either the GPL or the LGPL, and not to allow others to + use your version of this file under the terms of the MPL, indicate your + decision by deleting the provisions above and replace them with the notice + and other provisions required by the GPL or the LGPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the MPL, the GPL or the LGPL. + +*/ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Drawing.Text; +using System.Text; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using OpenHardwareMonitor.Hardware; +using OpenHardwareMonitor.Utilities; + +namespace OpenHardwareMonitor.GUI { + public class SensorNotifyIcon : IDisposable { + + private ISensor sensor; + private NotifyIcon notifyIcon; + private Bitmap bitmap; + private Graphics graphics; + private int majorVersion; + + public SensorNotifyIcon(SensorSystemTray sensorSystemTray, ISensor sensor) { + this.sensor = sensor; + this.notifyIcon = new NotifyIcon(); + this.majorVersion = Environment.OSVersion.Version.Major; + + ContextMenuStrip contextMenuStrip = new ContextMenuStrip(); + ToolStripMenuItem item = new ToolStripMenuItem("Remove"); + item.Click += delegate(object obj, EventArgs args) { + sensorSystemTray.Remove(sensor); + }; + contextMenuStrip.Items.Add(item); + this.notifyIcon.ContextMenuStrip = contextMenuStrip; + + this.bitmap = new Bitmap(16, 16, PixelFormat.Format32bppArgb); + this.graphics = Graphics.FromImage(this.bitmap); + this.graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; + this.graphics.SmoothingMode = SmoothingMode.HighQuality; + } + + public ISensor Sensor { + get { return sensor; } + } + + public void Dispose() { + Icon icon = notifyIcon.Icon; + notifyIcon.Icon = null; + if (icon != null) + icon.Dispose(); + notifyIcon.Dispose(); + notifyIcon = null; + + graphics.Dispose(); + graphics = null; + bitmap.Dispose(); + bitmap = null; + } + + private string GetString() { + switch (sensor.SensorType) { + case SensorType.Voltage: + return string.Format("{0:F11}", sensor.Value); + case SensorType.Clock: + return string.Format("{0:F11}", 1e-3f * sensor.Value); + case SensorType.Load: + return string.Format("{0:F0}", sensor.Value < 99 ? sensor.Value : 99); + case SensorType.Temperature: + return string.Format("{0:F0}", sensor.Value); + case SensorType.Fan: + return string.Format("{0:F11}", 1e-3f * sensor.Value); + } + return "-"; + } + + private Icon CreateSimpleIcon() { + + graphics.Clear(SystemColors.ButtonFace); + TextRenderer.DrawText(graphics, GetString(), SystemFonts.StatusFont, + new Point(-2, 0), Color.Blue, SystemColors.ButtonFace); + + BitmapData data = bitmap.LockBits( + new Rectangle(0, 0, bitmap.Width, bitmap.Height), + ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + + int stride = data.Stride; + IntPtr Scan0 = data.Scan0; + + int numBytes = bitmap.Width * bitmap.Height * 4; + byte[] bytes = new byte[numBytes]; + Marshal.Copy(Scan0, bytes, 0, numBytes); + bitmap.UnlockBits(data); + + return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb); + } + + private Icon CreateTransparentIcon() { + + graphics.Clear(Color.Black); + TextRenderer.DrawText(graphics, GetString(), SystemFonts.StatusFont, + new Point(-2, 0), Color.White, Color.Black); + + BitmapData data = bitmap.LockBits( + new Rectangle(0, 0, bitmap.Width, bitmap.Height), + ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + + int stride = data.Stride; + IntPtr Scan0 = data.Scan0; + + int numBytes = bitmap.Width * bitmap.Height * 4; + byte[] bytes = new byte[numBytes]; + Marshal.Copy(Scan0, bytes, 0, numBytes); + bitmap.UnlockBits(data); + + byte red, green, blue; + for (int i = 0; i < bytes.Length; i += 4) { + blue = bytes[i]; + green = bytes[i + 1]; + red = bytes[i + 2]; + + bytes[i] = 255; + bytes[i + 1] = 255; + bytes[i + 2] = 255; + bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue); + } + + return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb); + } + + public void Update() { + Icon icon = notifyIcon.Icon; + + if (majorVersion < 6) { + notifyIcon.Icon = CreateSimpleIcon(); + } else { + notifyIcon.Icon = CreateTransparentIcon(); + } + + if (icon != null) + icon.Dispose(); + + string format = ""; + switch (sensor.SensorType) { + case SensorType.Voltage: format = "{0}\n{1}: {2:F2} V"; break; + case SensorType.Clock: format = "{0}\n{1}: {2:F0} MHz"; break; + case SensorType.Load: format = "{0}\n{1}: {2:F1} %"; break; + case SensorType.Temperature: format = "{0}\n{1}: {2:F1} °C"; break; + case SensorType.Fan: format = "{0}\n{1}: {2:F0} RPM"; break; + } + + notifyIcon.Text = string.Format(format, + sensor.Hardware.Name, sensor.Name, sensor.Value); + notifyIcon.Visible = true; + } + } +} diff -r 654696eeebe8 -r 2392f7402fb6 GUI/SensorSystemTray.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GUI/SensorSystemTray.cs Fri Feb 12 00:36:56 2010 +0000 @@ -0,0 +1,121 @@ +/* + + Version: MPL 1.1/GPL 2.0/LGPL 2.1 + + The contents of this file are subject to the Mozilla Public License Version + 1.1 (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + The Original Code is the Open Hardware Monitor code. + + The Initial Developer of the Original Code is + Michael Möller . + Portions created by the Initial Developer are Copyright (C) 2009-2010 + the Initial Developer. All Rights Reserved. + + Contributor(s): + + Alternatively, the contents of this file may be used under the terms of + either the GNU General Public License Version 2 or later (the "GPL"), or + the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + in which case the provisions of the GPL or the LGPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of either the GPL or the LGPL, and not to allow others to + use your version of this file under the terms of the MPL, indicate your + decision by deleting the provisions above and replace them with the notice + and other provisions required by the GPL or the LGPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the MPL, the GPL or the LGPL. + +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using OpenHardwareMonitor.Hardware; +using OpenHardwareMonitor.Utilities; + +namespace OpenHardwareMonitor.GUI { + public class SensorSystemTray : IDisposable { + private Computer computer; + private List list = new List(); + + public SensorSystemTray(Computer computer) { + this.computer = computer; + computer.HardwareAdded += new HardwareEventHandler(HardwareAdded); + computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved); + } + + private void HardwareRemoved(IHardware hardware) { + hardware.SensorAdded -= new SensorEventHandler(SensorAdded); + hardware.SensorRemoved -= new SensorEventHandler(SensorRemoved); + foreach (ISensor sensor in hardware.Sensors) + SensorRemoved(sensor); + } + + private void HardwareAdded(IHardware hardware) { + foreach (ISensor sensor in hardware.Sensors) + SensorAdded(sensor); + hardware.SensorAdded += new SensorEventHandler(SensorAdded); + hardware.SensorRemoved += new SensorEventHandler(SensorRemoved); + } + + private void SensorAdded(ISensor sensor) { + if (Config.Get(sensor.Identifier + "/tray", false)) + Add(sensor); + } + + private void SensorRemoved(ISensor sensor) { + if (Contains(sensor)) { + Remove(sensor); + Config.Set(sensor.Identifier + "/tray", true); + } + } + + public void Dispose() { + foreach (SensorNotifyIcon icon in list) + icon.Dispose(); + } + + public void Redraw() { + foreach (SensorNotifyIcon icon in list) + icon.Update(); + } + + public bool Contains(ISensor sensor) { + foreach (SensorNotifyIcon icon in list) + if (icon.Sensor == sensor) + return true; + return false; + } + + public void Add(ISensor sensor) { + if (Contains(sensor)) { + return; + } else { + list.Add(new SensorNotifyIcon(this, sensor)); + Config.Set(sensor.Identifier + "/tray", true); + } + } + + public void Remove(ISensor sensor) { + Config.Remove(sensor.Identifier + "/tray"); + SensorNotifyIcon instance = null; + foreach (SensorNotifyIcon icon in list) + if (icon.Sensor == sensor) + instance = icon; + if (instance != null) { + list.Remove(instance); + instance.Dispose(); + } + } + + } +} diff -r 654696eeebe8 -r 2392f7402fb6 OpenHardwareMonitor.csproj --- a/OpenHardwareMonitor.csproj Thu Feb 11 13:22:17 2010 +0000 +++ b/OpenHardwareMonitor.csproj Fri Feb 12 00:36:56 2010 +0000 @@ -58,6 +58,8 @@ + + @@ -101,6 +103,7 @@ + UserControl @@ -139,13 +142,16 @@ - + + + + diff -r 654696eeebe8 -r 2392f7402fb6 Properties/AssemblyInfo.cs --- a/Properties/AssemblyInfo.cs Thu Feb 11 13:22:17 2010 +0000 +++ b/Properties/AssemblyInfo.cs Fri Feb 12 00:36:56 2010 +0000 @@ -69,5 +69,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.17.1")] -[assembly: AssemblyFileVersion("0.1.17.1")] +[assembly: AssemblyVersion("0.1.18.0")] +[assembly: AssemblyFileVersion("0.1.18.0")] diff -r 654696eeebe8 -r 2392f7402fb6 Utilities/IconFactory.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utilities/IconFactory.cs Fri Feb 12 00:36:56 2010 +0000 @@ -0,0 +1,203 @@ +/* + + Version: MPL 1.1/GPL 2.0/LGPL 2.1 + + The contents of this file are subject to the Mozilla Public License Version + 1.1 (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + The Original Code is the Open Hardware Monitor code. + + The Initial Developer of the Original Code is + Michael Möller . + Portions created by the Initial Developer are Copyright (C) 2009-2010 + the Initial Developer. All Rights Reserved. + + Contributor(s): + + Alternatively, the contents of this file may be used under the terms of + either the GNU General Public License Version 2 or later (the "GPL"), or + the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + in which case the provisions of the GPL or the LGPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of either the GPL or the LGPL, and not to allow others to + use your version of this file under the terms of the MPL, indicate your + decision by deleting the provisions above and replace them with the notice + and other provisions required by the GPL or the LGPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the MPL, the GPL or the LGPL. + +*/ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Text; + +namespace OpenHardwareMonitor.Utilities { + public class IconFactory { + + private struct BITMAPINFOHEADER { + public uint Size; + public int Width; + public int Height; + public ushort Planes; + public ushort BitCount; + public uint Compression; + public uint SizeImage; + public int XPelsPerMeter; + public int YPelsPerMeter; + public uint ClrUsed; + public uint ClrImportant; + + public BITMAPINFOHEADER(int width, int height, int bitCount) { + this.Size = 40; + this.Width = width; + this.Height = height; + this.Planes = 1; + this.BitCount = (ushort)bitCount; + this.Compression = 0; + this.SizeImage = 0; + this.XPelsPerMeter = 0; + this.YPelsPerMeter = 0; + this.ClrUsed = 0; + this.ClrImportant = 0; + } + + public void Write(BinaryWriter bw) { + bw.Write(Size); + bw.Write(Width); + bw.Write(Height); + bw.Write(Planes); + bw.Write(BitCount); + bw.Write(Compression); + bw.Write(SizeImage); + bw.Write(XPelsPerMeter); + bw.Write(YPelsPerMeter); + bw.Write(ClrUsed); + bw.Write(ClrImportant); + } + } + + private struct ICONIMAGE { + public BITMAPINFOHEADER Header; + public byte[] Colors; + public byte[] XOR; + public byte[] AND; + + public ICONIMAGE(int width, int height, byte[] colors) { + this.Header = new BITMAPINFOHEADER(width, height << 1, + (8 * colors.Length) / (width * height)); + this.Colors = colors; + int maskSize = (width * height) >> 3; + this.XOR = new byte[maskSize]; + this.AND = new byte[maskSize]; + } + + public void Write(BinaryWriter bw) { + Header.Write(bw); + int stride = Header.Width << 2; + for (int i = (Header.Height >> 1) - 1; i >= 0; i--) + bw.Write(Colors, i * stride, stride); + bw.Write(XOR); + bw.Write(AND); + } + } + + private struct ICONDIRENTRY { + public byte Width; + public byte Height; + public byte ColorCount; + public byte Reserved; + public ushort Planes; + public ushort BitCount; + public uint BytesInRes; + public uint ImageOffset; + + public ICONDIRENTRY(ICONIMAGE image, int imageOffset) { + this.Width = (byte)image.Header.Width; + this.Height = (byte)(image.Header.Height >> 1); + this.ColorCount = 0; + this.Reserved = 0; + this.Planes = image.Header.Planes; + this.BitCount = image.Header.BitCount; + this.BytesInRes = (uint)(image.Header.Size + + image.Colors.Length + image.XOR.Length + image.AND.Length); + this.ImageOffset = (uint)imageOffset; + } + + public void Write(BinaryWriter bw) { + bw.Write(Width); + bw.Write(Height); + bw.Write(ColorCount); + bw.Write(Reserved); + bw.Write(Planes); + bw.Write(BitCount); + bw.Write(BytesInRes); + bw.Write(ImageOffset); + } + + public uint Size { + get { return 16; } + } + } + + private struct ICONDIR { + public ushort Reserved; + public ushort Type; + public ushort Count; + public ICONDIRENTRY[] Entries; + + public ICONDIR(ICONDIRENTRY[] entries) { + this.Reserved = 0; + this.Type = 1; + this.Count = (ushort)entries.Length; + this.Entries = entries; + } + + public void Write(BinaryWriter bw) { + bw.Write(Reserved); + bw.Write(Type); + bw.Write(Count); + for (int i = 0; i < Entries.Length; i++) + Entries[i].Write(bw); + } + + public uint Size { + get { return (uint)(6 + Entries.Length * + (Entries.Length > 0 ? Entries[0].Size : 0)); } + } + } + + public static Icon Create(byte[] colors, int width, int height, + PixelFormat format) { + if (format != PixelFormat.Format32bppArgb) + throw new NotImplementedException(); + + ICONIMAGE image = new ICONIMAGE(width, height, colors); + ICONDIR dir = new ICONDIR( + new ICONDIRENTRY[] { new ICONDIRENTRY(image, 0) } ); + dir.Entries[0].ImageOffset = dir.Size; + + Icon icon; + using (BinaryWriter bw = new BinaryWriter(new MemoryStream())) { + dir.Write(bw); + image.Write(bw); + + bw.BaseStream.Position = 0; + icon = new Icon(bw.BaseStream); + } + + return icon; + } + + } +}