mirror of
https://github.com/openhardwaremonitor/openhardwaremonitor
synced 2025-08-22 09:57:20 +00:00
Fixed Issue 269.
This commit is contained in:
parent
fc026664d3
commit
0d43433aa4
502
GUI/NotifyIconAdv.cs
Normal file
502
GUI/NotifyIconAdv.cs
Normal file
@ -0,0 +1,502 @@
|
||||
/*
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
Copyright (C) 2012 Michael Möller <mmoeller@openhardwaremonitor.org>
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenHardwareMonitor.GUI {
|
||||
public class NotifyIconAdv : Component {
|
||||
|
||||
private static int nextId = 0;
|
||||
|
||||
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;
|
||||
|
||||
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 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; }
|
||||
|
||||
public Icon Icon {
|
||||
get {
|
||||
return icon;
|
||||
}
|
||||
set {
|
||||
if (icon != value) {
|
||||
icon = value;
|
||||
UpdateNotifyIcon(visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Text {
|
||||
get {
|
||||
return text;
|
||||
}
|
||||
set {
|
||||
if (value == null)
|
||||
value = "";
|
||||
|
||||
if (value.Length > 63)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
if (!value.Equals(text)) {
|
||||
text = value;
|
||||
|
||||
if (visible)
|
||||
UpdateNotifyIcon(visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Visible {
|
||||
get {
|
||||
return visible;
|
||||
}
|
||||
set {
|
||||
if (visible != value) {
|
||||
visible = value;
|
||||
UpdateNotifyIcon(visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 ShowBalloonTip(int timeout) {
|
||||
ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
UpdateNotifyIcon(visible);
|
||||
}
|
||||
|
||||
window.DefWndProc(ref message);
|
||||
}
|
||||
|
||||
private class NotifyIconNativeWindow : NativeWindow {
|
||||
private NotifyIconAdv reference;
|
||||
private GCHandle referenceHandle;
|
||||
|
||||
internal NotifyIconNativeWindow(NotifyIconAdv 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ namespace OpenHardwareMonitor.GUI {
|
||||
private UnitManager unitManager;
|
||||
|
||||
private ISensor sensor;
|
||||
private NotifyIcon notifyIcon;
|
||||
private NotifyIconAdv notifyIcon;
|
||||
private Bitmap bitmap;
|
||||
private Graphics graphics;
|
||||
private Color color;
|
||||
@ -40,7 +40,7 @@ namespace OpenHardwareMonitor.GUI {
|
||||
{
|
||||
this.unitManager = unitManager;
|
||||
this.sensor = sensor;
|
||||
this.notifyIcon = new NotifyIcon();
|
||||
this.notifyIcon = new NotifyIconAdv();
|
||||
|
||||
Color defaultColor = Color.Black;
|
||||
if (sensor.SensorType == SensorType.Load ||
|
||||
|
@ -23,7 +23,7 @@ namespace OpenHardwareMonitor.GUI {
|
||||
private UnitManager unitManager;
|
||||
private List<SensorNotifyIcon> list = new List<SensorNotifyIcon>();
|
||||
private bool mainIconEnabled = false;
|
||||
private NotifyIcon mainIcon;
|
||||
private NotifyIconAdv mainIcon;
|
||||
|
||||
public SystemTray(IComputer computer, PersistentSettings settings,
|
||||
UnitManager unitManager)
|
||||
@ -34,7 +34,7 @@ namespace OpenHardwareMonitor.GUI {
|
||||
computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
|
||||
computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);
|
||||
|
||||
this.mainIcon = new NotifyIcon();
|
||||
this.mainIcon = new NotifyIconAdv();
|
||||
|
||||
ContextMenu contextMenu = new ContextMenu();
|
||||
MenuItem hideShowItem = new MenuItem("Hide/Show");
|
||||
|
@ -73,6 +73,9 @@
|
||||
<Compile Include="GUI\GadgetWindow.cs" />
|
||||
<Compile Include="GUI\Gadget.cs" />
|
||||
<Compile Include="GUI\HardwareTypeImage.cs" />
|
||||
<Compile Include="GUI\NotifyIconAdv.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="GUI\PlotPanel.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
|
Loading…
x
Reference in New Issue
Block a user