moel@363: /*
moel@363:  
moel@363:   This Source Code Form is subject to the terms of the Mozilla Public
moel@363:   License, v. 2.0. If a copy of the MPL was not distributed with this
moel@363:   file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@363:  
moel@363:   Copyright (C) 2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@363: 	
moel@363: */
moel@363: 
moel@363: using System;
moel@363: using System.ComponentModel;
moel@363: using System.Drawing;
moel@363: using System.Runtime.InteropServices;
moel@363: using System.Reflection;
moel@363: using System.Windows.Forms;
moel@363: 
moel@363: namespace OpenHardwareMonitor.GUI {
moel@363: 
moel@371:   public class NotifyIconAdv : IDisposable {
moel@363: 
moel@371:     private NotifyIcon genericNotifyIcon;
moel@371:     private NotifyIconWindowsImplementation windowsNotifyIcon;
moel@363: 
moel@371:     public NotifyIconAdv() {
moel@371:       int p = (int)Environment.OSVersion.Platform;
moel@371:       if ((p == 4) || (p == 128)) { // Unix
moel@371:         genericNotifyIcon = new NotifyIcon();
moel@371:       } else { // Windows
moel@371:         windowsNotifyIcon = new NotifyIconWindowsImplementation();
moel@371:       }
moel@371:     }
moel@363: 
moel@371:     public event EventHandler BalloonTipClicked {
moel@371:       add {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.BalloonTipClicked += value;
moel@371:         else
moel@371:           windowsNotifyIcon.BalloonTipClicked += value;
moel@371:       }
moel@371:       remove {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.BalloonTipClicked -= value;
moel@371:         else
moel@371:           windowsNotifyIcon.BalloonTipClicked -= value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public event EventHandler BalloonTipClosed {
moel@371:       add {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.BalloonTipClosed += value;
moel@371:         else
moel@371:           windowsNotifyIcon.BalloonTipClosed += value;
moel@371:       }
moel@371:       remove {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.BalloonTipClosed -= value;
moel@371:         else
moel@371:           windowsNotifyIcon.BalloonTipClosed -= value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public event EventHandler BalloonTipShown {
moel@371:       add {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.BalloonTipShown += value;
moel@371:         else
moel@371:           windowsNotifyIcon.BalloonTipShown += value;
moel@371:       }
moel@371:       remove {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.BalloonTipShown -= value;
moel@371:         else
moel@371:           windowsNotifyIcon.BalloonTipShown -= value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public event EventHandler Click {
moel@371:       add {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.Click += value;
moel@371:         else
moel@371:           windowsNotifyIcon.Click += value;
moel@371:       }
moel@371:       remove {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.Click -= value;
moel@371:         else
moel@371:           windowsNotifyIcon.Click -= value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public event EventHandler DoubleClick {
moel@371:       add {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.DoubleClick += value;
moel@371:         else
moel@371:           windowsNotifyIcon.DoubleClick += value;
moel@371:       }
moel@371:       remove {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.DoubleClick -= value;
moel@371:         else
moel@371:           windowsNotifyIcon.DoubleClick -= value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public event MouseEventHandler MouseClick {
moel@371:       add {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.MouseClick += value;
moel@371:         else
moel@371:           windowsNotifyIcon.MouseClick += value;
moel@371:       }
moel@371:       remove {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.MouseClick -= value;
moel@371:         else
moel@371:           windowsNotifyIcon.MouseClick -= value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public event MouseEventHandler MouseDoubleClick {
moel@371:       add {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.MouseDoubleClick += value;
moel@371:         else
moel@371:           windowsNotifyIcon.MouseDoubleClick += value;
moel@371:       }
moel@371:       remove {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.MouseDoubleClick -= value;
moel@371:         else
moel@371:           windowsNotifyIcon.MouseDoubleClick -= value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public event MouseEventHandler MouseDown {
moel@371:       add {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.MouseDown += value;
moel@371:         else
moel@371:           windowsNotifyIcon.MouseDown += value;
moel@371:       }
moel@371:       remove {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.MouseDown -= value;
moel@371:         else
moel@371:           windowsNotifyIcon.MouseDown -= value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public event MouseEventHandler MouseMove {
moel@371:       add {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.MouseMove += value;
moel@371:         else
moel@371:           windowsNotifyIcon.MouseMove += value;
moel@371:       }
moel@371:       remove {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.MouseMove -= value;
moel@371:         else
moel@371:           windowsNotifyIcon.MouseMove -= value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public event MouseEventHandler MouseUp {
moel@371:       add {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.MouseUp += value;
moel@371:         else
moel@371:           windowsNotifyIcon.MouseUp += value;
moel@371:       }
moel@371:       remove {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.MouseUp -= value;
moel@371:         else
moel@371:           windowsNotifyIcon.MouseUp -= value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public string BalloonTipText {
moel@371:       get {
moel@371:         if (genericNotifyIcon != null)
moel@371:           return genericNotifyIcon.BalloonTipText;
moel@371:         else
moel@371:           return windowsNotifyIcon.BalloonTipText;
moel@371:       }
moel@371:       set {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.BalloonTipText = value;
moel@371:         else
moel@371:           windowsNotifyIcon.BalloonTipText = value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public ToolTipIcon BalloonTipIcon {
moel@371:       get {
moel@371:         if (genericNotifyIcon != null)
moel@371:           return genericNotifyIcon.BalloonTipIcon;
moel@371:         else
moel@371:           return windowsNotifyIcon.BalloonTipIcon;
moel@371:       }
moel@371:       set {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.BalloonTipIcon = value;
moel@371:         else
moel@371:           windowsNotifyIcon.BalloonTipIcon = value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public string BalloonTipTitle {
moel@371:       get {
moel@371:         if (genericNotifyIcon != null)
moel@371:           return genericNotifyIcon.BalloonTipTitle;
moel@371:         else
moel@371:           return windowsNotifyIcon.BalloonTipTitle;
moel@371:       }
moel@371:       set {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.BalloonTipTitle = value;
moel@371:         else
moel@371:           windowsNotifyIcon.BalloonTipTitle = value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public ContextMenu ContextMenu {
moel@371:       get {
moel@371:         if (genericNotifyIcon != null)
moel@371:           return genericNotifyIcon.ContextMenu;
moel@371:         else
moel@371:           return windowsNotifyIcon.ContextMenu;
moel@371:       }
moel@371:       set {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.ContextMenu = value;
moel@371:         else
moel@371:           windowsNotifyIcon.ContextMenu = value;
moel@371:       }
moel@371:     }
moel@371: 
moel@371:     public ContextMenuStrip ContextMenuStrip {
moel@371:       get {
moel@371:         if (genericNotifyIcon != null)
moel@371:           return genericNotifyIcon.ContextMenuStrip;
moel@371:         else
moel@371:           return windowsNotifyIcon.ContextMenuStrip;
moel@371:       }
moel@371:       set {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.ContextMenuStrip = value;
moel@371:         else
moel@371:           windowsNotifyIcon.ContextMenuStrip = value;
moel@371:       }
moel@371:     }
moel@371: 
moel@363:     public object Tag { get; set; }
moel@363: 
moel@363:     public Icon Icon {
moel@363:       get {
moel@371:         if (genericNotifyIcon != null)
moel@371:           return genericNotifyIcon.Icon;
moel@371:         else
moel@371:           return windowsNotifyIcon.Icon;
moel@363:       }
moel@363:       set {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.Icon = value;
moel@371:         else
moel@371:           windowsNotifyIcon.Icon = value;
moel@363:       }
moel@363:     }
moel@363: 
moel@363:     public string Text {
moel@363:       get {
moel@371:         if (genericNotifyIcon != null)
moel@371:           return genericNotifyIcon.Text;
moel@371:         else
moel@371:           return windowsNotifyIcon.Text;
moel@363:       }
moel@363:       set {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.Text = value;
moel@371:         else
moel@371:           windowsNotifyIcon.Text = value;
moel@363:       }
moel@363:     }
moel@363: 
moel@363:     public bool Visible {
moel@363:       get {
moel@371:         if (genericNotifyIcon != null)
moel@371:           return genericNotifyIcon.Visible;
moel@371:         else
moel@371:           return windowsNotifyIcon.Visible;
moel@363:       }
moel@363:       set {
moel@371:         if (genericNotifyIcon != null)
moel@371:           genericNotifyIcon.Visible = value;
moel@371:         else
moel@371:           windowsNotifyIcon.Visible = value;
moel@363:       }
moel@363:     }
moel@363: 
moel@371:     public void Dispose() {
moel@371:       if (genericNotifyIcon != null)
moel@371:         genericNotifyIcon.Dispose();
moel@371:       else
moel@371:         windowsNotifyIcon.Dispose();
moel@363:     }
moel@363: 
moel@363:     public void ShowBalloonTip(int timeout) {
moel@363:       ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
moel@363:     }
moel@363: 
moel@363:     public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
moel@371:       ToolTipIcon tipIcon) {
moel@371:       if (genericNotifyIcon != null)
moel@371:         genericNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
moel@371:       else
moel@371:         windowsNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
moel@371:     }
moel@371:     
moel@371:     private class NotifyIconWindowsImplementation : Component {
moel@363: 
moel@371:       private static int nextId = 0;
moel@363: 
moel@371:       private object syncObj = new object();
moel@371:       private Icon icon;
moel@371:       private string text = "";
moel@371:       private int id;
moel@371:       private bool created;
moel@371:       private NotifyIconNativeWindow window;
moel@371:       private bool doubleClickDown;
moel@371:       private bool visible;
moel@371:       private MethodInfo commandDispatch;
moel@363: 
moel@371:       public event EventHandler BalloonTipClicked;
moel@371:       public event EventHandler BalloonTipClosed;
moel@371:       public event EventHandler BalloonTipShown;
moel@371:       public event EventHandler Click;
moel@371:       public event EventHandler DoubleClick;
moel@371:       public event MouseEventHandler MouseClick;
moel@371:       public event MouseEventHandler MouseDoubleClick;
moel@371:       public event MouseEventHandler MouseDown;
moel@371:       public event MouseEventHandler MouseMove;
moel@371:       public event MouseEventHandler MouseUp;
moel@363: 
moel@371:       public string BalloonTipText { get; set; }
moel@371:       public ToolTipIcon BalloonTipIcon { get; set; }
moel@371:       public string BalloonTipTitle { get; set; }
moel@371:       public ContextMenu ContextMenu { get; set; }
moel@371:       public ContextMenuStrip ContextMenuStrip { get; set; }
moel@371:       public object Tag { get; set; }
moel@363: 
moel@371:       public Icon Icon {
moel@371:         get {
moel@371:           return icon;
moel@363:         }
moel@371:         set {
moel@371:           if (icon != value) {
moel@371:             icon = value;
moel@371:             UpdateNotifyIcon(visible);
moel@363:           }
moel@363:         }
moel@363:       }
moel@363: 
moel@371:       public string Text {
moel@371:         get {
moel@371:           return text;
moel@371:         }
moel@371:         set {
moel@371:           if (value == null)
moel@371:             value = "";
moel@363: 
moel@371:           if (value.Length > 63)
moel@371:             throw new ArgumentOutOfRangeException();
moel@363: 
moel@371:           if (!value.Equals(text)) {
moel@371:             text = value;
moel@371: 
moel@371:             if (visible)
moel@371:               UpdateNotifyIcon(visible);
moel@371:           }
moel@371:         }
moel@363:       }
moel@363: 
moel@371:       public bool Visible {
moel@371:         get {
moel@371:           return visible;
moel@371:         }
moel@371:         set {
moel@371:           if (visible != value) {
moel@371:             visible = value;
moel@371:             UpdateNotifyIcon(visible);
moel@363:           }
moel@371:         }
moel@363:       }
moel@363: 
moel@371:       public NotifyIconWindowsImplementation() {
moel@371:         BalloonTipText = "";
moel@371:         BalloonTipTitle = "";
moel@371: 
moel@371:         commandDispatch = typeof(Form).Assembly.
moel@371:           GetType("System.Windows.Forms.Command").GetMethod("DispatchID",
moel@371:           BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
moel@371:           null, new Type[] { typeof(int) }, null);
moel@371: 
moel@371:         id = ++NotifyIconWindowsImplementation.nextId;
moel@371:         window = new NotifyIconNativeWindow(this);
moel@363:         UpdateNotifyIcon(visible);
moel@363:       }
moel@363: 
moel@371:       protected override void Dispose(bool disposing) {
moel@371:         if (disposing) {
moel@371:           if (window != null) {
moel@371:             icon = null;
moel@371:             text = "";
moel@371:             UpdateNotifyIcon(false);
moel@371:             window.DestroyHandle();
moel@371:             window = null;
moel@371:             ContextMenu = null;
moel@371:             ContextMenuStrip = null;
moel@371:           }
moel@371:         } else {
moel@371:           if (window != null && window.Handle != IntPtr.Zero) {
moel@371:             NativeMethods.PostMessage(
moel@371:               new HandleRef(window, window.Handle), WM_CLOSE, 0, 0);
moel@371:             window.ReleaseHandle();
moel@371:           }
moel@371:         }
moel@371:         base.Dispose(disposing);
moel@363:       }
moel@363: 
moel@371:       public void ShowBalloonTip(int timeout) {
moel@371:         ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
moel@363:       }
moel@363: 
moel@371:       public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
moel@371:         ToolTipIcon tipIcon) {
moel@371:         if (timeout < 0)
moel@371:           throw new ArgumentOutOfRangeException("timeout");
moel@371: 
moel@371:         if (string.IsNullOrEmpty(tipText))
moel@371:           throw new ArgumentException("tipText");
moel@371: 
moel@371:         if (DesignMode)
moel@371:           return;
moel@371: 
moel@371:         if (created) {
moel@371:           NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
moel@371:           if (window.Handle == IntPtr.Zero)
moel@371:             window.CreateHandle(new CreateParams());
moel@371: 
moel@371:           data.Window = window.Handle;
moel@371:           data.ID = id;
moel@371:           data.Flags = NativeMethods.NotifyIconDataFlags.Info;
moel@371:           data.TimeoutOrVersion = timeout;
moel@371:           data.InfoTitle = tipTitle;
moel@371:           data.Info = tipText;
moel@371:           data.InfoFlags = (int)tipIcon;
moel@371: 
moel@371:           NativeMethods.Shell_NotifyIcon(
moel@371:             NativeMethods.NotifyIconMessage.Modify, data);
moel@363:         }
moel@363:       }
moel@363: 
moel@371:       private void ShowContextMenu() {
moel@371:         if (ContextMenu == null && ContextMenuStrip == null)
moel@371:           return;
moel@371: 
moel@371:         NativeMethods.Point p = new NativeMethods.Point();
moel@371:         NativeMethods.GetCursorPos(ref p);
moel@371:         NativeMethods.SetForegroundWindow(
moel@371:           new HandleRef(window, window.Handle));
moel@371: 
moel@371:         if (ContextMenu != null) {
moel@371:           ContextMenu.GetType().InvokeMember("OnPopup",
moel@371:             BindingFlags.NonPublic | BindingFlags.InvokeMethod |
moel@371:             BindingFlags.Instance, null, ContextMenu,
moel@371:             new Object[] { System.EventArgs.Empty });
moel@371: 
moel@371:           NativeMethods.TrackPopupMenuEx(
moel@371:             new HandleRef(ContextMenu, ContextMenu.Handle), 72,
moel@371:             p.x, p.y, new HandleRef(window, window.Handle),
moel@371:             IntPtr.Zero);
moel@371: 
moel@371:           NativeMethods.PostMessage(
moel@371:             new HandleRef(window, window.Handle), WM_NULL, 0, 0);
moel@371:           return;
moel@371:         }
moel@371: 
moel@371:         if (ContextMenuStrip != null)
moel@371:           ContextMenuStrip.GetType().InvokeMember("ShowInTaskbar",
moel@371:             BindingFlags.NonPublic | BindingFlags.InvokeMethod |
moel@371:             BindingFlags.Instance, null, ContextMenuStrip,
moel@371:             new Object[] { p.x, p.y });
moel@363:       }
moel@363: 
moel@371:       private void UpdateNotifyIcon(bool showNotifyIcon) {
moel@371:         if (DesignMode)
moel@371:           return;
moel@363: 
moel@371:         lock (syncObj) {
moel@371:           window.LockReference(showNotifyIcon);
moel@363: 
moel@371:           NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
moel@371:           data.CallbackMessage = WM_TRAYMOUSEMESSAGE;
moel@371:           data.Flags = NativeMethods.NotifyIconDataFlags.Message;
moel@363: 
moel@371:           if (showNotifyIcon && window.Handle == IntPtr.Zero)
moel@371:             window.CreateHandle(new CreateParams());
moel@363: 
moel@371:           data.Window = window.Handle;
moel@371:           data.ID = id;
moel@363: 
moel@371:           if (icon != null) {
moel@371:             data.Flags |= NativeMethods.NotifyIconDataFlags.Icon;
moel@371:             data.Icon = icon.Handle;
moel@371:           }
moel@363: 
moel@371:           data.Flags |= NativeMethods.NotifyIconDataFlags.Tip;
moel@371:           data.Tip = text;
moel@371: 
moel@371:           if (showNotifyIcon && icon != null) {
moel@371:             if (!created) {
moel@371:               int i = 0;
moel@371:               do {
moel@371:                 created = NativeMethods.Shell_NotifyIcon(
moel@371:                   NativeMethods.NotifyIconMessage.Add, data);
moel@371:                 if (!created) {
moel@371:                   System.Threading.Thread.Sleep(200);
moel@371:                   i++;
moel@371:                 }
moel@371:               } while (!created && i < 40);
moel@371:             } else {
moel@371:               NativeMethods.Shell_NotifyIcon(
moel@371:                 NativeMethods.NotifyIconMessage.Modify, data);
moel@371:             }
moel@371:           } else {
moel@371:             if (created) {
moel@371:               int i = 0;
moel@371:               bool deleted = false;
moel@371:               do {
moel@371:                 deleted = NativeMethods.Shell_NotifyIcon(
moel@371:                   NativeMethods.NotifyIconMessage.Delete, data);
moel@371:                 if (!deleted) {
moel@371:                   System.Threading.Thread.Sleep(200);
moel@371:                   i++;
moel@371:                 }
moel@371:               } while (!deleted && i < 40);
moel@371:               created = false;
moel@371:             }
moel@371:           }
moel@371:         }
moel@363:       }
moel@363: 
moel@371:       private void ProcessMouseDown(ref Message message, MouseButtons button,
moel@371:         bool doubleClick) {
moel@371:         if (doubleClick) {
moel@371:           if (DoubleClick != null)
moel@371:             DoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
moel@371: 
moel@371:           if (MouseDoubleClick != null)
moel@371:             MouseDoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
moel@371: 
moel@371:           doubleClickDown = true;
moel@371:         }
moel@371: 
moel@371:         if (MouseDown != null)
moel@371:           MouseDown(this,
moel@371:             new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0));
moel@363:       }
moel@363: 
moel@371:       private void ProcessMouseUp(ref Message message, MouseButtons button) {
moel@371:         if (MouseUp != null)
moel@371:           MouseUp(this, new MouseEventArgs(button, 0, 0, 0, 0));
moel@371: 
moel@371:         if (!doubleClickDown) {
moel@371:           if (Click != null)
moel@371:             Click(this, new MouseEventArgs(button, 0, 0, 0, 0));
moel@371: 
moel@371:           if (MouseClick != null)
moel@371:             MouseClick(this, new MouseEventArgs(button, 0, 0, 0, 0));
moel@371:         }
moel@371:         doubleClickDown = false;
moel@363:       }
moel@363: 
moel@371:       private void ProcessInitMenuPopup(ref Message message) {
moel@371:         if (ContextMenu != null &&
moel@371:           (bool)ContextMenu.GetType().InvokeMember("ProcessInitMenuPopup",
moel@371:             BindingFlags.NonPublic | BindingFlags.InvokeMethod |
moel@371:             BindingFlags.Instance, null, ContextMenu,
moel@371:             new Object[] { message.WParam })) {
moel@371:           return;
moel@371:         }
moel@371:         window.DefWndProc(ref message);
moel@363:       }
moel@363: 
moel@371:       private void WndProc(ref Message message) {
moel@371:         switch (message.Msg) {
moel@371:           case WM_DESTROY:
moel@371:             UpdateNotifyIcon(false);
moel@371:             return;
moel@371:           case WM_COMMAND:
moel@371:             if (message.LParam != IntPtr.Zero) {
moel@371:               window.DefWndProc(ref message);
moel@371:               return;
moel@371:             }
moel@371:             commandDispatch.Invoke(null, new object[] { 
moel@371:             message.WParam.ToInt32() & 0xFFFF });
moel@371:             return;
moel@371:           case WM_INITMENUPOPUP:
moel@371:             ProcessInitMenuPopup(ref message);
moel@371:             return;
moel@371:           case WM_TRAYMOUSEMESSAGE:
moel@371:             switch ((int)message.LParam) {
moel@371:               case WM_MOUSEMOVE:
moel@371:                 if (MouseMove != null)
moel@371:                   MouseMove(this,
moel@371:                     new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0));
moel@371:                 return;
moel@371:               case WM_LBUTTONDOWN:
moel@371:                 ProcessMouseDown(ref message, MouseButtons.Left, false);
moel@371:                 return;
moel@371:               case WM_LBUTTONUP:
moel@371:                 ProcessMouseUp(ref message, MouseButtons.Left);
moel@371:                 return;
moel@371:               case WM_LBUTTONDBLCLK:
moel@371:                 ProcessMouseDown(ref message, MouseButtons.Left, true);
moel@371:                 return;
moel@371:               case WM_RBUTTONDOWN:
moel@371:                 ProcessMouseDown(ref message, MouseButtons.Right, false);
moel@371:                 return;
moel@371:               case WM_RBUTTONUP:
moel@371:                 if (ContextMenu != null || ContextMenuStrip != null)
moel@371:                   ShowContextMenu();
moel@371:                 ProcessMouseUp(ref message, MouseButtons.Right);
moel@371:                 return;
moel@371:               case WM_RBUTTONDBLCLK:
moel@371:                 ProcessMouseDown(ref message, MouseButtons.Right, true);
moel@371:                 return;
moel@371:               case WM_MBUTTONDOWN:
moel@371:                 ProcessMouseDown(ref message, MouseButtons.Middle, false);
moel@371:                 return;
moel@371:               case WM_MBUTTONUP:
moel@371:                 ProcessMouseUp(ref message, MouseButtons.Middle);
moel@371:                 return;
moel@371:               case WM_MBUTTONDBLCLK:
moel@371:                 ProcessMouseDown(ref message, MouseButtons.Middle, true);
moel@371:                 return;
moel@371:               case NIN_BALLOONSHOW:
moel@371:                 if (BalloonTipShown != null)
moel@371:                   BalloonTipShown(this, EventArgs.Empty);
moel@371:                 return;
moel@371:               case NIN_BALLOONHIDE:
moel@371:               case NIN_BALLOONTIMEOUT:
moel@371:                 if (BalloonTipClosed != null)
moel@371:                   BalloonTipClosed(this, EventArgs.Empty);
moel@371:                 return;
moel@371:               case NIN_BALLOONUSERCLICK:
moel@371:                 if (BalloonTipClicked != null)
moel@371:                   BalloonTipClicked(this, EventArgs.Empty);
moel@371:                 return;
moel@371:               default:
moel@371:                 return;
moel@371:             }
moel@371:         }
moel@363: 
moel@371:         if (message.Msg == NotifyIconWindowsImplementation.WM_TASKBARCREATED) {
moel@371:           lock (syncObj) {
moel@371:             created = false;
moel@371:           }
moel@371:           UpdateNotifyIcon(visible);
moel@371:         }
moel@371: 
moel@371:         window.DefWndProc(ref message);
moel@371:       }
moel@371: 
moel@371:       private class NotifyIconNativeWindow : NativeWindow {
moel@371:         private NotifyIconWindowsImplementation reference;
moel@371:         private GCHandle referenceHandle;
moel@371: 
moel@371:         internal NotifyIconNativeWindow(NotifyIconWindowsImplementation component) {
moel@371:           this.reference = component;
moel@371:         }
moel@371: 
moel@371:         ~NotifyIconNativeWindow() {
moel@371:           if (base.Handle != IntPtr.Zero)
moel@371:             NativeMethods.PostMessage(
moel@371:               new HandleRef(this, base.Handle), WM_CLOSE, 0, 0);
moel@371:         }
moel@371: 
moel@371:         public void LockReference(bool locked) {
moel@371:           if (locked) {
moel@371:             if (!referenceHandle.IsAllocated) {
moel@371:               referenceHandle = GCHandle.Alloc(reference, GCHandleType.Normal);
moel@371:               return;
moel@371:             }
moel@371:           } else {
moel@371:             if (referenceHandle.IsAllocated)
moel@371:               referenceHandle.Free();
moel@371:           }
moel@371:         }
moel@371: 
moel@371:         protected override void OnThreadException(Exception e) {
moel@371:           Application.OnThreadException(e);
moel@371:         }
moel@371: 
moel@371:         protected override void WndProc(ref Message m) {
moel@371:           reference.WndProc(ref m);
moel@371:         }
moel@371:       }
moel@371: 
moel@371:       private const int WM_NULL = 0x00;
moel@371:       private const int WM_DESTROY = 0x02;
moel@371:       private const int WM_CLOSE = 0x10;
moel@371:       private const int WM_COMMAND = 0x111;
moel@371:       private const int WM_INITMENUPOPUP = 0x117;
moel@371:       private const int WM_MOUSEMOVE = 0x200;
moel@371:       private const int WM_LBUTTONDOWN = 0x201;
moel@371:       private const int WM_LBUTTONUP = 0x202;
moel@371:       private const int WM_LBUTTONDBLCLK = 0x203;
moel@371:       private const int WM_RBUTTONDOWN = 0x204;
moel@371:       private const int WM_RBUTTONUP = 0x205;
moel@371:       private const int WM_RBUTTONDBLCLK = 0x206;
moel@371:       private const int WM_MBUTTONDOWN = 0x207;
moel@371:       private const int WM_MBUTTONUP = 0x208;
moel@371:       private const int WM_MBUTTONDBLCLK = 0x209;
moel@371:       private const int WM_TRAYMOUSEMESSAGE = 0x800;
moel@371: 
moel@371:       private const int NIN_BALLOONSHOW = 0x402;
moel@371:       private const int NIN_BALLOONHIDE = 0x403;
moel@371:       private const int NIN_BALLOONTIMEOUT = 0x404;
moel@371:       private const int NIN_BALLOONUSERCLICK = 0x405;
moel@371: 
moel@371:       private static int WM_TASKBARCREATED =
moel@371:         NativeMethods.RegisterWindowMessage("TaskbarCreated");
moel@371: 
moel@371:       private static class NativeMethods {
moel@371:         [DllImport("user32.dll", CharSet = CharSet.Auto)]
moel@371:         public static extern IntPtr PostMessage(HandleRef hwnd, int msg,
moel@371:           int wparam, int lparam);
moel@371: 
moel@371:         [DllImport("user32.dll", CharSet = CharSet.Auto)]
moel@371:         public static extern int RegisterWindowMessage(string msg);
moel@371: 
moel@371:         [Flags]
moel@371:         public enum NotifyIconDataFlags : int {
moel@371:           Message = 0x1,
moel@371:           Icon = 0x2,
moel@371:           Tip = 0x4,
moel@371:           State = 0x8,
moel@371:           Info = 0x10
moel@371:         }
moel@371: 
moel@371:         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
moel@371:         public class NotifyIconData {
moel@371:           private int Size = Marshal.SizeOf(typeof(NotifyIconData));
moel@371:           public IntPtr Window;
moel@371:           public int ID;
moel@371:           public NotifyIconDataFlags Flags;
moel@371:           public int CallbackMessage;
moel@371:           public IntPtr Icon;
moel@371:           [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
moel@371:           public string Tip;
moel@371:           public int State;
moel@371:           public int StateMask;
moel@371:           [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
moel@371:           public string Info;
moel@371:           public int TimeoutOrVersion;
moel@371:           [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
moel@371:           public string InfoTitle;
moel@371:           public int InfoFlags;
moel@371:         }
moel@371: 
moel@371:         public enum NotifyIconMessage : int {
moel@371:           Add = 0x0,
moel@371:           Modify = 0x1,
moel@371:           Delete = 0x2
moel@371:         }
moel@371: 
moel@371:         [DllImport("shell32.dll", CharSet = CharSet.Auto)]
moel@371:         [return: MarshalAs(UnmanagedType.Bool)]
moel@371:         public static extern bool Shell_NotifyIcon(NotifyIconMessage message,
moel@371:           NotifyIconData pnid);
moel@371: 
moel@371:         [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
moel@371:         public static extern bool TrackPopupMenuEx(HandleRef hmenu, int fuFlags,
moel@371:           int x, int y, HandleRef hwnd, IntPtr tpm);
moel@371: 
moel@371:         [StructLayout(LayoutKind.Sequential)]
moel@371:         public struct Point {
moel@371:           public int x;
moel@371:           public int y;
moel@371:         }
moel@371: 
moel@371:         [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
moel@371:         public static extern bool GetCursorPos(ref Point point);
moel@371: 
moel@371:         [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
moel@371:         public static extern bool SetForegroundWindow(HandleRef hWnd);
moel@371:       }
moel@363:     }
moel@363:   }
moel@363: }