# HG changeset patch
# User moel.mich
# Date 1343145870 0
# Node ID c1a0d321e6460974d90dfe8c5593f6e71597c03f
# Parent  8e4dedc41924348029f83736558110a3e8737a1c
Added a wrapper for the NotifyIconAdv to use the normal NotifyIcon class on Linux systems and the (fixed) custom implementation on Windows systems.
diff -r 8e4dedc41924 -r c1a0d321e646 GUI/NotifyIconAdv.cs
--- a/GUI/NotifyIconAdv.cs	Mon Jul 23 21:54:35 2012 +0000
+++ b/GUI/NotifyIconAdv.cs	Tue Jul 24 16:04:30 2012 +0000
@@ -16,115 +16,298 @@
 using System.Windows.Forms;
 
 namespace OpenHardwareMonitor.GUI {
-  public class NotifyIconAdv : Component {
 
-    private static int nextId = 0;
+  public class NotifyIconAdv : IDisposable {
 
-    private object syncObj = new object();
-    private Icon icon;
-    private string text = "";
-    private int id;
-    private bool created;
-    private NotifyIconNativeWindow window;
-    private bool doubleClickDown;
-    private bool visible;
-    private MethodInfo commandDispatch;
+    private NotifyIcon genericNotifyIcon;
+    private NotifyIconWindowsImplementation windowsNotifyIcon;
 
-    public event EventHandler BalloonTipClicked;
-    public event EventHandler BalloonTipClosed;
-    public event EventHandler BalloonTipShown;
-    public event EventHandler Click;
-    public event EventHandler DoubleClick;
-    public event MouseEventHandler MouseClick;
-    public event MouseEventHandler MouseDoubleClick;
-    public event MouseEventHandler MouseDown;
-    public event MouseEventHandler MouseMove;
-    public event MouseEventHandler MouseUp;
+    public NotifyIconAdv() {
+      int p = (int)Environment.OSVersion.Platform;
+      if ((p == 4) || (p == 128)) { // Unix
+        genericNotifyIcon = new NotifyIcon();
+      } else { // Windows
+        windowsNotifyIcon = new NotifyIconWindowsImplementation();
+      }
+    }
 
-    public string BalloonTipText { get; set; }
-    public ToolTipIcon BalloonTipIcon { get; set; }
-    public string BalloonTipTitle { get; set; }
-    public ContextMenu ContextMenu { get; set; }
-    public ContextMenuStrip ContextMenuStrip { get; set; }
+    public event EventHandler BalloonTipClicked {
+      add {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.BalloonTipClicked += value;
+        else
+          windowsNotifyIcon.BalloonTipClicked += value;
+      }
+      remove {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.BalloonTipClicked -= value;
+        else
+          windowsNotifyIcon.BalloonTipClicked -= value;
+      }
+    }
+
+    public event EventHandler BalloonTipClosed {
+      add {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.BalloonTipClosed += value;
+        else
+          windowsNotifyIcon.BalloonTipClosed += value;
+      }
+      remove {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.BalloonTipClosed -= value;
+        else
+          windowsNotifyIcon.BalloonTipClosed -= value;
+      }
+    }
+
+    public event EventHandler BalloonTipShown {
+      add {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.BalloonTipShown += value;
+        else
+          windowsNotifyIcon.BalloonTipShown += value;
+      }
+      remove {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.BalloonTipShown -= value;
+        else
+          windowsNotifyIcon.BalloonTipShown -= value;
+      }
+    }
+
+    public event EventHandler Click {
+      add {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.Click += value;
+        else
+          windowsNotifyIcon.Click += value;
+      }
+      remove {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.Click -= value;
+        else
+          windowsNotifyIcon.Click -= value;
+      }
+    }
+
+    public event EventHandler DoubleClick {
+      add {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.DoubleClick += value;
+        else
+          windowsNotifyIcon.DoubleClick += value;
+      }
+      remove {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.DoubleClick -= value;
+        else
+          windowsNotifyIcon.DoubleClick -= value;
+      }
+    }
+
+    public event MouseEventHandler MouseClick {
+      add {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.MouseClick += value;
+        else
+          windowsNotifyIcon.MouseClick += value;
+      }
+      remove {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.MouseClick -= value;
+        else
+          windowsNotifyIcon.MouseClick -= value;
+      }
+    }
+
+    public event MouseEventHandler MouseDoubleClick {
+      add {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.MouseDoubleClick += value;
+        else
+          windowsNotifyIcon.MouseDoubleClick += value;
+      }
+      remove {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.MouseDoubleClick -= value;
+        else
+          windowsNotifyIcon.MouseDoubleClick -= value;
+      }
+    }
+
+    public event MouseEventHandler MouseDown {
+      add {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.MouseDown += value;
+        else
+          windowsNotifyIcon.MouseDown += value;
+      }
+      remove {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.MouseDown -= value;
+        else
+          windowsNotifyIcon.MouseDown -= value;
+      }
+    }
+
+    public event MouseEventHandler MouseMove {
+      add {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.MouseMove += value;
+        else
+          windowsNotifyIcon.MouseMove += value;
+      }
+      remove {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.MouseMove -= value;
+        else
+          windowsNotifyIcon.MouseMove -= value;
+      }
+    }
+
+    public event MouseEventHandler MouseUp {
+      add {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.MouseUp += value;
+        else
+          windowsNotifyIcon.MouseUp += value;
+      }
+      remove {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.MouseUp -= value;
+        else
+          windowsNotifyIcon.MouseUp -= value;
+      }
+    }
+
+    public string BalloonTipText {
+      get {
+        if (genericNotifyIcon != null)
+          return genericNotifyIcon.BalloonTipText;
+        else
+          return windowsNotifyIcon.BalloonTipText;
+      }
+      set {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.BalloonTipText = value;
+        else
+          windowsNotifyIcon.BalloonTipText = value;
+      }
+    }
+
+    public ToolTipIcon BalloonTipIcon {
+      get {
+        if (genericNotifyIcon != null)
+          return genericNotifyIcon.BalloonTipIcon;
+        else
+          return windowsNotifyIcon.BalloonTipIcon;
+      }
+      set {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.BalloonTipIcon = value;
+        else
+          windowsNotifyIcon.BalloonTipIcon = value;
+      }
+    }
+
+    public string BalloonTipTitle {
+      get {
+        if (genericNotifyIcon != null)
+          return genericNotifyIcon.BalloonTipTitle;
+        else
+          return windowsNotifyIcon.BalloonTipTitle;
+      }
+      set {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.BalloonTipTitle = value;
+        else
+          windowsNotifyIcon.BalloonTipTitle = value;
+      }
+    }
+
+    public ContextMenu ContextMenu {
+      get {
+        if (genericNotifyIcon != null)
+          return genericNotifyIcon.ContextMenu;
+        else
+          return windowsNotifyIcon.ContextMenu;
+      }
+      set {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.ContextMenu = value;
+        else
+          windowsNotifyIcon.ContextMenu = value;
+      }
+    }
+
+    public ContextMenuStrip ContextMenuStrip {
+      get {
+        if (genericNotifyIcon != null)
+          return genericNotifyIcon.ContextMenuStrip;
+        else
+          return windowsNotifyIcon.ContextMenuStrip;
+      }
+      set {
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.ContextMenuStrip = value;
+        else
+          windowsNotifyIcon.ContextMenuStrip = value;
+      }
+    }
+
     public object Tag { get; set; }
 
     public Icon Icon {
       get {
-        return icon;
+        if (genericNotifyIcon != null)
+          return genericNotifyIcon.Icon;
+        else
+          return windowsNotifyIcon.Icon;
       }
       set {
-        if (icon != value) {
-          icon = value;
-          UpdateNotifyIcon(visible);
-        }
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.Icon = value;
+        else
+          windowsNotifyIcon.Icon = value;
       }
     }
 
     public string Text {
       get {
-        return text;
+        if (genericNotifyIcon != null)
+          return genericNotifyIcon.Text;
+        else
+          return windowsNotifyIcon.Text;
       }
       set {
-        if (value == null)
-          value = "";
-
-        if (value.Length > 63)
-          throw new ArgumentOutOfRangeException();
-
-        if (!value.Equals(text)) {
-          text = value;
-
-          if (visible) 
-            UpdateNotifyIcon(visible);          
-        }
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.Text = value;
+        else
+          windowsNotifyIcon.Text = value;
       }
     }
 
     public bool Visible {
       get {
-        return visible;
+        if (genericNotifyIcon != null)
+          return genericNotifyIcon.Visible;
+        else
+          return windowsNotifyIcon.Visible;
       }
       set {
-        if (visible != value) {
-          visible = value;
-          UpdateNotifyIcon(visible);          
-        }
+        if (genericNotifyIcon != null)
+          genericNotifyIcon.Visible = value;
+        else
+          windowsNotifyIcon.Visible = value;
       }
     }
-    
-    public NotifyIconAdv() {
-      BalloonTipText = "";
-      BalloonTipTitle = "";
 
-      commandDispatch = typeof(Form).Assembly.
-        GetType("System.Windows.Forms.Command").GetMethod("DispatchID",
-        BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
-        null, new Type[] { typeof(int) }, null);
-
-      id = ++NotifyIconAdv.nextId;
-      window = new NotifyIconNativeWindow(this);
-      UpdateNotifyIcon(visible);
-    }
-
-    protected override void Dispose(bool disposing) {
-      if (disposing) {
-        if (window != null) {
-          icon = null;
-          text = "";
-          UpdateNotifyIcon(false);
-          window.DestroyHandle();
-          window = null;
-          ContextMenu = null;
-          ContextMenuStrip = null;
-        }
-      } else {
-        if (window != null && window.Handle != IntPtr.Zero) {
-          NativeMethods.PostMessage(
-            new HandleRef(window, window.Handle), WM_CLOSE, 0, 0);
-          window.ReleaseHandle();
-        }
-      }
-      base.Dispose(disposing);
+    public void Dispose() {
+      if (genericNotifyIcon != null)
+        genericNotifyIcon.Dispose();
+      else
+        windowsNotifyIcon.Dispose();
     }
 
     public void ShowBalloonTip(int timeout) {
@@ -132,371 +315,493 @@
     }
 
     public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
-      ToolTipIcon tipIcon) 
-    {
-      if (timeout < 0)
-        throw new ArgumentOutOfRangeException("timeout");
+      ToolTipIcon tipIcon) {
+      if (genericNotifyIcon != null)
+        genericNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
+      else
+        windowsNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
+    }
+    
+    private class NotifyIconWindowsImplementation : Component {
 
-      if (string.IsNullOrEmpty(tipText))
-        throw new ArgumentException("tipText");
+      private static int nextId = 0;
 
-      if (DesignMode)
-        return;
+      private object syncObj = new object();
+      private Icon icon;
+      private string text = "";
+      private int id;
+      private bool created;
+      private NotifyIconNativeWindow window;
+      private bool doubleClickDown;
+      private bool visible;
+      private MethodInfo commandDispatch;
 
-      if (created) {
-        NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
-        if (window.Handle == IntPtr.Zero)
-          window.CreateHandle(new CreateParams());
+      public event EventHandler BalloonTipClicked;
+      public event EventHandler BalloonTipClosed;
+      public event EventHandler BalloonTipShown;
+      public event EventHandler Click;
+      public event EventHandler DoubleClick;
+      public event MouseEventHandler MouseClick;
+      public event MouseEventHandler MouseDoubleClick;
+      public event MouseEventHandler MouseDown;
+      public event MouseEventHandler MouseMove;
+      public event MouseEventHandler MouseUp;
 
-        data.Window = window.Handle;
-        data.ID = id;
-        data.Flags = NativeMethods.NotifyIconDataFlags.Info;
-        data.TimeoutOrVersion = timeout;
-        data.InfoTitle = tipTitle;
-        data.Info = tipText;
-        data.InfoFlags = (int)tipIcon;
+      public string BalloonTipText { get; set; }
+      public ToolTipIcon BalloonTipIcon { get; set; }
+      public string BalloonTipTitle { get; set; }
+      public ContextMenu ContextMenu { get; set; }
+      public ContextMenuStrip ContextMenuStrip { get; set; }
+      public object Tag { get; set; }
 
-        NativeMethods.Shell_NotifyIcon(
-          NativeMethods.NotifyIconMessage.Modify, data);
-      }
-    }
-
-    private void ShowContextMenu() {
-      if (ContextMenu == null && ContextMenuStrip == null)
-        return;
-
-      NativeMethods.Point p = new NativeMethods.Point();
-      NativeMethods.GetCursorPos(ref p);
-      NativeMethods.SetForegroundWindow(
-        new HandleRef(window, window.Handle));
-
-      if (ContextMenu != null) {
-        ContextMenu.GetType().InvokeMember("OnPopup",
-          BindingFlags.NonPublic | BindingFlags.InvokeMethod |
-          BindingFlags.Instance, null, ContextMenu,
-          new Object[] { System.EventArgs.Empty });
-
-        NativeMethods.TrackPopupMenuEx(
-          new HandleRef(ContextMenu, ContextMenu.Handle), 72,
-          p.x, p.y, new HandleRef(window, window.Handle),
-          IntPtr.Zero);
-
-        NativeMethods.PostMessage(
-          new HandleRef(window, window.Handle), WM_NULL, 0, 0);
-        return;
-      }
-
-      if (ContextMenuStrip != null)
-        ContextMenuStrip.GetType().InvokeMember("ShowInTaskbar",
-          BindingFlags.NonPublic | BindingFlags.InvokeMethod |
-          BindingFlags.Instance, null, ContextMenuStrip,
-          new Object[] { p.x, p.y });
-    }
-
-    private void UpdateNotifyIcon(bool showNotifyIcon) {
-      if (DesignMode)
-        return;
-
-      lock (syncObj) {
-        window.LockReference(showNotifyIcon);
-
-        NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
-        data.CallbackMessage = WM_TRAYMOUSEMESSAGE;
-        data.Flags = NativeMethods.NotifyIconDataFlags.Message;
-
-        if (showNotifyIcon && window.Handle == IntPtr.Zero)
-          window.CreateHandle(new CreateParams());
-
-        data.Window = window.Handle;
-        data.ID = id;
-
-        if (icon != null) {
-          data.Flags |= NativeMethods.NotifyIconDataFlags.Icon;
-          data.Icon = icon.Handle;
+      public Icon Icon {
+        get {
+          return icon;
         }
-
-        data.Flags |= NativeMethods.NotifyIconDataFlags.Tip;
-        data.Tip = text;
-
-        if (showNotifyIcon && icon != null) {
-          if (!created) {
-            int i = 0;
-            do {
-              created = NativeMethods.Shell_NotifyIcon(
-                NativeMethods.NotifyIconMessage.Add, data);
-              if (!created) {
-                System.Threading.Thread.Sleep(200);
-                i++;
-              }
-            } while (!created && i < 40);
-          } else {
-            NativeMethods.Shell_NotifyIcon(
-              NativeMethods.NotifyIconMessage.Modify, data);
-          }
-        } else {
-          if (created) {
-            int i = 0;
-            bool deleted = false;
-            do {
-              deleted = NativeMethods.Shell_NotifyIcon(
-                NativeMethods.NotifyIconMessage.Delete, data);
-              if (!deleted) {
-                System.Threading.Thread.Sleep(200);
-                i++;
-              }
-            } while (!deleted && i < 40);
-            created = false;
+        set {
+          if (icon != value) {
+            icon = value;
+            UpdateNotifyIcon(visible);
           }
         }
       }
-    }
 
-    private void ProcessMouseDown(ref Message message, MouseButtons button, 
-      bool doubleClick) 
-    {
-      if (doubleClick) {
-        if (DoubleClick != null)
-          DoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
+      public string Text {
+        get {
+          return text;
+        }
+        set {
+          if (value == null)
+            value = "";
 
-        if (MouseDoubleClick != null)
-          MouseDoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
+          if (value.Length > 63)
+            throw new ArgumentOutOfRangeException();
 
-        doubleClickDown = true;
+          if (!value.Equals(text)) {
+            text = value;
+
+            if (visible)
+              UpdateNotifyIcon(visible);
+          }
+        }
       }
 
-      if (MouseDown != null)
-        MouseDown(this, 
-          new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0));      
-    }
-
-    private void ProcessMouseUp(ref Message message, MouseButtons button) {
-      if (MouseUp != null)
-        MouseUp(this, new MouseEventArgs(button, 0, 0, 0, 0));
-
-      if (!doubleClickDown) {
-        if (Click != null)
-          Click(this, new MouseEventArgs(button, 0, 0, 0, 0));
-
-        if (MouseClick != null)
-          MouseClick(this, new MouseEventArgs(button, 0, 0, 0, 0));
-      }
-      doubleClickDown = false;
-    }
-
-    private void ProcessInitMenuPopup(ref Message message) {
-      if (ContextMenu != null &&
-        (bool)ContextMenu.GetType().InvokeMember("ProcessInitMenuPopup",
-          BindingFlags.NonPublic | BindingFlags.InvokeMethod |
-          BindingFlags.Instance, null, ContextMenu,
-          new Object[] { message.WParam })) {
-        return;
-      }
-      window.DefWndProc(ref message);
-    }
-
-    private void WndProc(ref Message message) {
-      switch (message.Msg) {
-        case WM_DESTROY:
-          UpdateNotifyIcon(false);
-          return;
-        case WM_COMMAND:
-          if (message.LParam != IntPtr.Zero) {
-            window.DefWndProc(ref message);
-            return;
+      public bool Visible {
+        get {
+          return visible;
+        }
+        set {
+          if (visible != value) {
+            visible = value;
+            UpdateNotifyIcon(visible);
           }
-          commandDispatch.Invoke(null, new object[] { 
-            message.WParam.ToInt32() & 0xFFFF });
-          return;
-        case WM_INITMENUPOPUP:
-          ProcessInitMenuPopup(ref message);
-          return;
-        case WM_TRAYMOUSEMESSAGE:
-          switch ((int)message.LParam) {
-            case WM_MOUSEMOVE:
-              if (MouseMove != null)
-                MouseMove(this, 
-                  new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0));              
-              return;
-            case WM_LBUTTONDOWN:
-              ProcessMouseDown(ref message, MouseButtons.Left, false);
-              return;
-            case WM_LBUTTONUP:
-              ProcessMouseUp(ref message, MouseButtons.Left);
-              return;
-            case WM_LBUTTONDBLCLK:
-              ProcessMouseDown(ref message, MouseButtons.Left, true);
-              return;
-            case WM_RBUTTONDOWN:
-              ProcessMouseDown(ref message, MouseButtons.Right, false);
-              return;
-            case WM_RBUTTONUP:
-              if (ContextMenu != null || ContextMenuStrip != null)
-                ShowContextMenu();
-              ProcessMouseUp(ref message, MouseButtons.Right);
-              return;
-            case WM_RBUTTONDBLCLK:
-              ProcessMouseDown(ref message, MouseButtons.Right, true);
-              return;
-            case WM_MBUTTONDOWN:
-              ProcessMouseDown(ref message, MouseButtons.Middle, false);
-              return;
-            case WM_MBUTTONUP:
-              ProcessMouseUp(ref message, MouseButtons.Middle);
-              return;
-            case WM_MBUTTONDBLCLK:
-              ProcessMouseDown(ref message, MouseButtons.Middle, true);
-              return;
-            case NIN_BALLOONSHOW:
-              if (BalloonTipShown != null)
-                BalloonTipShown(this, EventArgs.Empty);
-              return;
-            case NIN_BALLOONHIDE:
-            case NIN_BALLOONTIMEOUT:
-              if (BalloonTipClosed != null)
-                BalloonTipClosed(this, EventArgs.Empty);
-              return;
-            case NIN_BALLOONUSERCLICK:
-              if (BalloonTipClicked != null)
-                BalloonTipClicked(this, EventArgs.Empty);
-              return;
-            default:
-              return;
-          }
+        }
       }
 
-      if (message.Msg == NotifyIconAdv.WM_TASKBARCREATED) {
-        lock (syncObj) {
-          created = false;
-        }
+      public NotifyIconWindowsImplementation() {
+        BalloonTipText = "";
+        BalloonTipTitle = "";
+
+        commandDispatch = typeof(Form).Assembly.
+          GetType("System.Windows.Forms.Command").GetMethod("DispatchID",
+          BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
+          null, new Type[] { typeof(int) }, null);
+
+        id = ++NotifyIconWindowsImplementation.nextId;
+        window = new NotifyIconNativeWindow(this);
         UpdateNotifyIcon(visible);
       }
 
-      window.DefWndProc(ref message);
-    }
-
-    private class NotifyIconNativeWindow : NativeWindow {
-      private NotifyIconAdv reference;
-      private GCHandle referenceHandle;
-
-      internal NotifyIconNativeWindow(NotifyIconAdv component) {
-        this.reference = component;
+      protected override void Dispose(bool disposing) {
+        if (disposing) {
+          if (window != null) {
+            icon = null;
+            text = "";
+            UpdateNotifyIcon(false);
+            window.DestroyHandle();
+            window = null;
+            ContextMenu = null;
+            ContextMenuStrip = null;
+          }
+        } else {
+          if (window != null && window.Handle != IntPtr.Zero) {
+            NativeMethods.PostMessage(
+              new HandleRef(window, window.Handle), WM_CLOSE, 0, 0);
+            window.ReleaseHandle();
+          }
+        }
+        base.Dispose(disposing);
       }
 
-      ~NotifyIconNativeWindow() {
-        if (base.Handle != IntPtr.Zero)
-          NativeMethods.PostMessage(
-            new HandleRef(this, base.Handle), WM_CLOSE, 0, 0);
+      public void ShowBalloonTip(int timeout) {
+        ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
       }
 
-      public void LockReference(bool locked) {
-        if (locked) {
-          if (!referenceHandle.IsAllocated) {
-            referenceHandle = GCHandle.Alloc(reference, GCHandleType.Normal);
-            return;
-          }
-        } else {
-          if (referenceHandle.IsAllocated)
-            referenceHandle.Free();
+      public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
+        ToolTipIcon tipIcon) {
+        if (timeout < 0)
+          throw new ArgumentOutOfRangeException("timeout");
+
+        if (string.IsNullOrEmpty(tipText))
+          throw new ArgumentException("tipText");
+
+        if (DesignMode)
+          return;
+
+        if (created) {
+          NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
+          if (window.Handle == IntPtr.Zero)
+            window.CreateHandle(new CreateParams());
+
+          data.Window = window.Handle;
+          data.ID = id;
+          data.Flags = NativeMethods.NotifyIconDataFlags.Info;
+          data.TimeoutOrVersion = timeout;
+          data.InfoTitle = tipTitle;
+          data.Info = tipText;
+          data.InfoFlags = (int)tipIcon;
+
+          NativeMethods.Shell_NotifyIcon(
+            NativeMethods.NotifyIconMessage.Modify, data);
         }
       }
 
-      protected override void OnThreadException(Exception e) {
-        Application.OnThreadException(e);
+      private void ShowContextMenu() {
+        if (ContextMenu == null && ContextMenuStrip == null)
+          return;
+
+        NativeMethods.Point p = new NativeMethods.Point();
+        NativeMethods.GetCursorPos(ref p);
+        NativeMethods.SetForegroundWindow(
+          new HandleRef(window, window.Handle));
+
+        if (ContextMenu != null) {
+          ContextMenu.GetType().InvokeMember("OnPopup",
+            BindingFlags.NonPublic | BindingFlags.InvokeMethod |
+            BindingFlags.Instance, null, ContextMenu,
+            new Object[] { System.EventArgs.Empty });
+
+          NativeMethods.TrackPopupMenuEx(
+            new HandleRef(ContextMenu, ContextMenu.Handle), 72,
+            p.x, p.y, new HandleRef(window, window.Handle),
+            IntPtr.Zero);
+
+          NativeMethods.PostMessage(
+            new HandleRef(window, window.Handle), WM_NULL, 0, 0);
+          return;
+        }
+
+        if (ContextMenuStrip != null)
+          ContextMenuStrip.GetType().InvokeMember("ShowInTaskbar",
+            BindingFlags.NonPublic | BindingFlags.InvokeMethod |
+            BindingFlags.Instance, null, ContextMenuStrip,
+            new Object[] { p.x, p.y });
       }
 
-      protected override void WndProc(ref Message m) {
-        reference.WndProc(ref m);
-      }
-    }    
+      private void UpdateNotifyIcon(bool showNotifyIcon) {
+        if (DesignMode)
+          return;
 
-    private const int WM_NULL = 0x00;
-    private const int WM_DESTROY = 0x02;
-    private const int WM_CLOSE = 0x10;
-    private const int WM_COMMAND = 0x111;
-    private const int WM_INITMENUPOPUP = 0x117;
-    private const int WM_MOUSEMOVE = 0x200;
-    private const int WM_LBUTTONDOWN = 0x201;
-    private const int WM_LBUTTONUP = 0x202;
-    private const int WM_LBUTTONDBLCLK = 0x203;
-    private const int WM_RBUTTONDOWN = 0x204;
-    private const int WM_RBUTTONUP = 0x205;
-    private const int WM_RBUTTONDBLCLK = 0x206;
-    private const int WM_MBUTTONDOWN = 0x207;
-    private const int WM_MBUTTONUP = 0x208;
-    private const int WM_MBUTTONDBLCLK = 0x209;
-    private const int WM_TRAYMOUSEMESSAGE = 0x800;
+        lock (syncObj) {
+          window.LockReference(showNotifyIcon);
 
-    private const int NIN_BALLOONSHOW = 0x402;
-    private const int NIN_BALLOONHIDE = 0x403;
-    private const int NIN_BALLOONTIMEOUT = 0x404;
-    private const int NIN_BALLOONUSERCLICK = 0x405;
+          NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
+          data.CallbackMessage = WM_TRAYMOUSEMESSAGE;
+          data.Flags = NativeMethods.NotifyIconDataFlags.Message;
 
-    private static int WM_TASKBARCREATED =
-      NativeMethods.RegisterWindowMessage("TaskbarCreated");
+          if (showNotifyIcon && window.Handle == IntPtr.Zero)
+            window.CreateHandle(new CreateParams());
 
-    private static class NativeMethods {
-      [DllImport("user32.dll", CharSet = CharSet.Auto)]
-      public static extern IntPtr PostMessage(HandleRef hwnd, int msg,
-        int wparam, int lparam);
+          data.Window = window.Handle;
+          data.ID = id;
 
-      [DllImport("user32.dll", CharSet = CharSet.Auto)]
-      public static extern int RegisterWindowMessage(string msg);
+          if (icon != null) {
+            data.Flags |= NativeMethods.NotifyIconDataFlags.Icon;
+            data.Icon = icon.Handle;
+          }
 
-      [Flags]
-      public enum NotifyIconDataFlags : int {
-        Message = 0x1,
-        Icon = 0x2,
-        Tip = 0x4,
-        State = 0x8,
-        Info = 0x10
+          data.Flags |= NativeMethods.NotifyIconDataFlags.Tip;
+          data.Tip = text;
+
+          if (showNotifyIcon && icon != null) {
+            if (!created) {
+              int i = 0;
+              do {
+                created = NativeMethods.Shell_NotifyIcon(
+                  NativeMethods.NotifyIconMessage.Add, data);
+                if (!created) {
+                  System.Threading.Thread.Sleep(200);
+                  i++;
+                }
+              } while (!created && i < 40);
+            } else {
+              NativeMethods.Shell_NotifyIcon(
+                NativeMethods.NotifyIconMessage.Modify, data);
+            }
+          } else {
+            if (created) {
+              int i = 0;
+              bool deleted = false;
+              do {
+                deleted = NativeMethods.Shell_NotifyIcon(
+                  NativeMethods.NotifyIconMessage.Delete, data);
+                if (!deleted) {
+                  System.Threading.Thread.Sleep(200);
+                  i++;
+                }
+              } while (!deleted && i < 40);
+              created = false;
+            }
+          }
+        }
       }
 
-      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
-      public class NotifyIconData {
-        private int Size = Marshal.SizeOf(typeof(NotifyIconData));
-        public IntPtr Window;
-        public int ID;
-        public NotifyIconDataFlags Flags;
-        public int CallbackMessage;
-        public IntPtr Icon;
-        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
-        public string Tip;
-        public int State;
-        public int StateMask;
-        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
-        public string Info;
-        public int TimeoutOrVersion;
-        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
-        public string InfoTitle;
-        public int InfoFlags;
+      private void ProcessMouseDown(ref Message message, MouseButtons button,
+        bool doubleClick) {
+        if (doubleClick) {
+          if (DoubleClick != null)
+            DoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
+
+          if (MouseDoubleClick != null)
+            MouseDoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
+
+          doubleClickDown = true;
+        }
+
+        if (MouseDown != null)
+          MouseDown(this,
+            new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0));
       }
 
-      public enum NotifyIconMessage : int {
-        Add = 0x0,
-        Modify = 0x1,
-        Delete = 0x2
+      private void ProcessMouseUp(ref Message message, MouseButtons button) {
+        if (MouseUp != null)
+          MouseUp(this, new MouseEventArgs(button, 0, 0, 0, 0));
+
+        if (!doubleClickDown) {
+          if (Click != null)
+            Click(this, new MouseEventArgs(button, 0, 0, 0, 0));
+
+          if (MouseClick != null)
+            MouseClick(this, new MouseEventArgs(button, 0, 0, 0, 0));
+        }
+        doubleClickDown = false;
       }
 
-      [DllImport("shell32.dll", CharSet = CharSet.Auto)]
-      [return: MarshalAs(UnmanagedType.Bool)]
-      public static extern bool Shell_NotifyIcon(NotifyIconMessage message,
-        NotifyIconData pnid);
-
-      [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
-      public static extern bool TrackPopupMenuEx(HandleRef hmenu, int fuFlags,
-        int x, int y, HandleRef hwnd, IntPtr tpm);
-
-      [StructLayout(LayoutKind.Sequential)]
-      public struct Point {
-        public int x;
-        public int y;
+      private void ProcessInitMenuPopup(ref Message message) {
+        if (ContextMenu != null &&
+          (bool)ContextMenu.GetType().InvokeMember("ProcessInitMenuPopup",
+            BindingFlags.NonPublic | BindingFlags.InvokeMethod |
+            BindingFlags.Instance, null, ContextMenu,
+            new Object[] { message.WParam })) {
+          return;
+        }
+        window.DefWndProc(ref message);
       }
 
-      [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
-      public static extern bool GetCursorPos(ref Point point);
+      private void WndProc(ref Message message) {
+        switch (message.Msg) {
+          case WM_DESTROY:
+            UpdateNotifyIcon(false);
+            return;
+          case WM_COMMAND:
+            if (message.LParam != IntPtr.Zero) {
+              window.DefWndProc(ref message);
+              return;
+            }
+            commandDispatch.Invoke(null, new object[] { 
+            message.WParam.ToInt32() & 0xFFFF });
+            return;
+          case WM_INITMENUPOPUP:
+            ProcessInitMenuPopup(ref message);
+            return;
+          case WM_TRAYMOUSEMESSAGE:
+            switch ((int)message.LParam) {
+              case WM_MOUSEMOVE:
+                if (MouseMove != null)
+                  MouseMove(this,
+                    new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0));
+                return;
+              case WM_LBUTTONDOWN:
+                ProcessMouseDown(ref message, MouseButtons.Left, false);
+                return;
+              case WM_LBUTTONUP:
+                ProcessMouseUp(ref message, MouseButtons.Left);
+                return;
+              case WM_LBUTTONDBLCLK:
+                ProcessMouseDown(ref message, MouseButtons.Left, true);
+                return;
+              case WM_RBUTTONDOWN:
+                ProcessMouseDown(ref message, MouseButtons.Right, false);
+                return;
+              case WM_RBUTTONUP:
+                if (ContextMenu != null || ContextMenuStrip != null)
+                  ShowContextMenu();
+                ProcessMouseUp(ref message, MouseButtons.Right);
+                return;
+              case WM_RBUTTONDBLCLK:
+                ProcessMouseDown(ref message, MouseButtons.Right, true);
+                return;
+              case WM_MBUTTONDOWN:
+                ProcessMouseDown(ref message, MouseButtons.Middle, false);
+                return;
+              case WM_MBUTTONUP:
+                ProcessMouseUp(ref message, MouseButtons.Middle);
+                return;
+              case WM_MBUTTONDBLCLK:
+                ProcessMouseDown(ref message, MouseButtons.Middle, true);
+                return;
+              case NIN_BALLOONSHOW:
+                if (BalloonTipShown != null)
+                  BalloonTipShown(this, EventArgs.Empty);
+                return;
+              case NIN_BALLOONHIDE:
+              case NIN_BALLOONTIMEOUT:
+                if (BalloonTipClosed != null)
+                  BalloonTipClosed(this, EventArgs.Empty);
+                return;
+              case NIN_BALLOONUSERCLICK:
+                if (BalloonTipClicked != null)
+                  BalloonTipClicked(this, EventArgs.Empty);
+                return;
+              default:
+                return;
+            }
+        }
 
-      [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
-      public static extern bool SetForegroundWindow(HandleRef hWnd);
+        if (message.Msg == NotifyIconWindowsImplementation.WM_TASKBARCREATED) {
+          lock (syncObj) {
+            created = false;
+          }
+          UpdateNotifyIcon(visible);
+        }
+
+        window.DefWndProc(ref message);
+      }
+
+      private class NotifyIconNativeWindow : NativeWindow {
+        private NotifyIconWindowsImplementation reference;
+        private GCHandle referenceHandle;
+
+        internal NotifyIconNativeWindow(NotifyIconWindowsImplementation component) {
+          this.reference = component;
+        }
+
+        ~NotifyIconNativeWindow() {
+          if (base.Handle != IntPtr.Zero)
+            NativeMethods.PostMessage(
+              new HandleRef(this, base.Handle), WM_CLOSE, 0, 0);
+        }
+
+        public void LockReference(bool locked) {
+          if (locked) {
+            if (!referenceHandle.IsAllocated) {
+              referenceHandle = GCHandle.Alloc(reference, GCHandleType.Normal);
+              return;
+            }
+          } else {
+            if (referenceHandle.IsAllocated)
+              referenceHandle.Free();
+          }
+        }
+
+        protected override void OnThreadException(Exception e) {
+          Application.OnThreadException(e);
+        }
+
+        protected override void WndProc(ref Message m) {
+          reference.WndProc(ref m);
+        }
+      }
+
+      private const int WM_NULL = 0x00;
+      private const int WM_DESTROY = 0x02;
+      private const int WM_CLOSE = 0x10;
+      private const int WM_COMMAND = 0x111;
+      private const int WM_INITMENUPOPUP = 0x117;
+      private const int WM_MOUSEMOVE = 0x200;
+      private const int WM_LBUTTONDOWN = 0x201;
+      private const int WM_LBUTTONUP = 0x202;
+      private const int WM_LBUTTONDBLCLK = 0x203;
+      private const int WM_RBUTTONDOWN = 0x204;
+      private const int WM_RBUTTONUP = 0x205;
+      private const int WM_RBUTTONDBLCLK = 0x206;
+      private const int WM_MBUTTONDOWN = 0x207;
+      private const int WM_MBUTTONUP = 0x208;
+      private const int WM_MBUTTONDBLCLK = 0x209;
+      private const int WM_TRAYMOUSEMESSAGE = 0x800;
+
+      private const int NIN_BALLOONSHOW = 0x402;
+      private const int NIN_BALLOONHIDE = 0x403;
+      private const int NIN_BALLOONTIMEOUT = 0x404;
+      private const int NIN_BALLOONUSERCLICK = 0x405;
+
+      private static int WM_TASKBARCREATED =
+        NativeMethods.RegisterWindowMessage("TaskbarCreated");
+
+      private static class NativeMethods {
+        [DllImport("user32.dll", CharSet = CharSet.Auto)]
+        public static extern IntPtr PostMessage(HandleRef hwnd, int msg,
+          int wparam, int lparam);
+
+        [DllImport("user32.dll", CharSet = CharSet.Auto)]
+        public static extern int RegisterWindowMessage(string msg);
+
+        [Flags]
+        public enum NotifyIconDataFlags : int {
+          Message = 0x1,
+          Icon = 0x2,
+          Tip = 0x4,
+          State = 0x8,
+          Info = 0x10
+        }
+
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+        public class NotifyIconData {
+          private int Size = Marshal.SizeOf(typeof(NotifyIconData));
+          public IntPtr Window;
+          public int ID;
+          public NotifyIconDataFlags Flags;
+          public int CallbackMessage;
+          public IntPtr Icon;
+          [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
+          public string Tip;
+          public int State;
+          public int StateMask;
+          [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
+          public string Info;
+          public int TimeoutOrVersion;
+          [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
+          public string InfoTitle;
+          public int InfoFlags;
+        }
+
+        public enum NotifyIconMessage : int {
+          Add = 0x0,
+          Modify = 0x1,
+          Delete = 0x2
+        }
+
+        [DllImport("shell32.dll", CharSet = CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool Shell_NotifyIcon(NotifyIconMessage message,
+          NotifyIconData pnid);
+
+        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
+        public static extern bool TrackPopupMenuEx(HandleRef hmenu, int fuFlags,
+          int x, int y, HandleRef hwnd, IntPtr tpm);
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct Point {
+          public int x;
+          public int y;
+        }
+
+        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
+        public static extern bool GetCursorPos(ref Point point);
+
+        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
+        public static extern bool SetForegroundWindow(HandleRef hWnd);
+      }
     }
   }
 }
diff -r 8e4dedc41924 -r c1a0d321e646 OpenHardwareMonitor.csproj
--- a/OpenHardwareMonitor.csproj	Mon Jul 23 21:54:35 2012 +0000
+++ b/OpenHardwareMonitor.csproj	Tue Jul 24 16:04:30 2012 +0000
@@ -73,9 +73,7 @@
     
     
     
-    
-      Component
-    
+    
     
       UserControl