GUI/NotifyIconAdv.cs
author moel.mich
Tue, 24 Jul 2012 16:04:30 +0000
changeset 371 c1a0d321e646
parent 363 daa9590e1bee
permissions -rw-r--r--
Added a wrapper for the NotifyIconAdv to use the normal NotifyIcon class on Linux systems and the (fixed) custom implementation on Windows systems.
moel@363
     1
/*
moel@363
     2
 
moel@363
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@363
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@363
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@363
     6
 
moel@363
     7
  Copyright (C) 2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@363
     8
	
moel@363
     9
*/
moel@363
    10
moel@363
    11
using System;
moel@363
    12
using System.ComponentModel;
moel@363
    13
using System.Drawing;
moel@363
    14
using System.Runtime.InteropServices;
moel@363
    15
using System.Reflection;
moel@363
    16
using System.Windows.Forms;
moel@363
    17
moel@363
    18
namespace OpenHardwareMonitor.GUI {
moel@363
    19
moel@371
    20
  public class NotifyIconAdv : IDisposable {
moel@363
    21
moel@371
    22
    private NotifyIcon genericNotifyIcon;
moel@371
    23
    private NotifyIconWindowsImplementation windowsNotifyIcon;
moel@363
    24
moel@371
    25
    public NotifyIconAdv() {
moel@371
    26
      int p = (int)Environment.OSVersion.Platform;
moel@371
    27
      if ((p == 4) || (p == 128)) { // Unix
moel@371
    28
        genericNotifyIcon = new NotifyIcon();
moel@371
    29
      } else { // Windows
moel@371
    30
        windowsNotifyIcon = new NotifyIconWindowsImplementation();
moel@371
    31
      }
moel@371
    32
    }
moel@363
    33
moel@371
    34
    public event EventHandler BalloonTipClicked {
moel@371
    35
      add {
moel@371
    36
        if (genericNotifyIcon != null)
moel@371
    37
          genericNotifyIcon.BalloonTipClicked += value;
moel@371
    38
        else
moel@371
    39
          windowsNotifyIcon.BalloonTipClicked += value;
moel@371
    40
      }
moel@371
    41
      remove {
moel@371
    42
        if (genericNotifyIcon != null)
moel@371
    43
          genericNotifyIcon.BalloonTipClicked -= value;
moel@371
    44
        else
moel@371
    45
          windowsNotifyIcon.BalloonTipClicked -= value;
moel@371
    46
      }
moel@371
    47
    }
moel@371
    48
moel@371
    49
    public event EventHandler BalloonTipClosed {
moel@371
    50
      add {
moel@371
    51
        if (genericNotifyIcon != null)
moel@371
    52
          genericNotifyIcon.BalloonTipClosed += value;
moel@371
    53
        else
moel@371
    54
          windowsNotifyIcon.BalloonTipClosed += value;
moel@371
    55
      }
moel@371
    56
      remove {
moel@371
    57
        if (genericNotifyIcon != null)
moel@371
    58
          genericNotifyIcon.BalloonTipClosed -= value;
moel@371
    59
        else
moel@371
    60
          windowsNotifyIcon.BalloonTipClosed -= value;
moel@371
    61
      }
moel@371
    62
    }
moel@371
    63
moel@371
    64
    public event EventHandler BalloonTipShown {
moel@371
    65
      add {
moel@371
    66
        if (genericNotifyIcon != null)
moel@371
    67
          genericNotifyIcon.BalloonTipShown += value;
moel@371
    68
        else
moel@371
    69
          windowsNotifyIcon.BalloonTipShown += value;
moel@371
    70
      }
moel@371
    71
      remove {
moel@371
    72
        if (genericNotifyIcon != null)
moel@371
    73
          genericNotifyIcon.BalloonTipShown -= value;
moel@371
    74
        else
moel@371
    75
          windowsNotifyIcon.BalloonTipShown -= value;
moel@371
    76
      }
moel@371
    77
    }
moel@371
    78
moel@371
    79
    public event EventHandler Click {
moel@371
    80
      add {
moel@371
    81
        if (genericNotifyIcon != null)
moel@371
    82
          genericNotifyIcon.Click += value;
moel@371
    83
        else
moel@371
    84
          windowsNotifyIcon.Click += value;
moel@371
    85
      }
moel@371
    86
      remove {
moel@371
    87
        if (genericNotifyIcon != null)
moel@371
    88
          genericNotifyIcon.Click -= value;
moel@371
    89
        else
moel@371
    90
          windowsNotifyIcon.Click -= value;
moel@371
    91
      }
moel@371
    92
    }
moel@371
    93
moel@371
    94
    public event EventHandler DoubleClick {
moel@371
    95
      add {
moel@371
    96
        if (genericNotifyIcon != null)
moel@371
    97
          genericNotifyIcon.DoubleClick += value;
moel@371
    98
        else
moel@371
    99
          windowsNotifyIcon.DoubleClick += value;
moel@371
   100
      }
moel@371
   101
      remove {
moel@371
   102
        if (genericNotifyIcon != null)
moel@371
   103
          genericNotifyIcon.DoubleClick -= value;
moel@371
   104
        else
moel@371
   105
          windowsNotifyIcon.DoubleClick -= value;
moel@371
   106
      }
moel@371
   107
    }
moel@371
   108
moel@371
   109
    public event MouseEventHandler MouseClick {
moel@371
   110
      add {
moel@371
   111
        if (genericNotifyIcon != null)
moel@371
   112
          genericNotifyIcon.MouseClick += value;
moel@371
   113
        else
moel@371
   114
          windowsNotifyIcon.MouseClick += value;
moel@371
   115
      }
moel@371
   116
      remove {
moel@371
   117
        if (genericNotifyIcon != null)
moel@371
   118
          genericNotifyIcon.MouseClick -= value;
moel@371
   119
        else
moel@371
   120
          windowsNotifyIcon.MouseClick -= value;
moel@371
   121
      }
moel@371
   122
    }
moel@371
   123
moel@371
   124
    public event MouseEventHandler MouseDoubleClick {
moel@371
   125
      add {
moel@371
   126
        if (genericNotifyIcon != null)
moel@371
   127
          genericNotifyIcon.MouseDoubleClick += value;
moel@371
   128
        else
moel@371
   129
          windowsNotifyIcon.MouseDoubleClick += value;
moel@371
   130
      }
moel@371
   131
      remove {
moel@371
   132
        if (genericNotifyIcon != null)
moel@371
   133
          genericNotifyIcon.MouseDoubleClick -= value;
moel@371
   134
        else
moel@371
   135
          windowsNotifyIcon.MouseDoubleClick -= value;
moel@371
   136
      }
moel@371
   137
    }
moel@371
   138
moel@371
   139
    public event MouseEventHandler MouseDown {
moel@371
   140
      add {
moel@371
   141
        if (genericNotifyIcon != null)
moel@371
   142
          genericNotifyIcon.MouseDown += value;
moel@371
   143
        else
moel@371
   144
          windowsNotifyIcon.MouseDown += value;
moel@371
   145
      }
moel@371
   146
      remove {
moel@371
   147
        if (genericNotifyIcon != null)
moel@371
   148
          genericNotifyIcon.MouseDown -= value;
moel@371
   149
        else
moel@371
   150
          windowsNotifyIcon.MouseDown -= value;
moel@371
   151
      }
moel@371
   152
    }
moel@371
   153
moel@371
   154
    public event MouseEventHandler MouseMove {
moel@371
   155
      add {
moel@371
   156
        if (genericNotifyIcon != null)
moel@371
   157
          genericNotifyIcon.MouseMove += value;
moel@371
   158
        else
moel@371
   159
          windowsNotifyIcon.MouseMove += value;
moel@371
   160
      }
moel@371
   161
      remove {
moel@371
   162
        if (genericNotifyIcon != null)
moel@371
   163
          genericNotifyIcon.MouseMove -= value;
moel@371
   164
        else
moel@371
   165
          windowsNotifyIcon.MouseMove -= value;
moel@371
   166
      }
moel@371
   167
    }
moel@371
   168
moel@371
   169
    public event MouseEventHandler MouseUp {
moel@371
   170
      add {
moel@371
   171
        if (genericNotifyIcon != null)
moel@371
   172
          genericNotifyIcon.MouseUp += value;
moel@371
   173
        else
moel@371
   174
          windowsNotifyIcon.MouseUp += value;
moel@371
   175
      }
moel@371
   176
      remove {
moel@371
   177
        if (genericNotifyIcon != null)
moel@371
   178
          genericNotifyIcon.MouseUp -= value;
moel@371
   179
        else
moel@371
   180
          windowsNotifyIcon.MouseUp -= value;
moel@371
   181
      }
moel@371
   182
    }
moel@371
   183
moel@371
   184
    public string BalloonTipText {
moel@371
   185
      get {
moel@371
   186
        if (genericNotifyIcon != null)
moel@371
   187
          return genericNotifyIcon.BalloonTipText;
moel@371
   188
        else
moel@371
   189
          return windowsNotifyIcon.BalloonTipText;
moel@371
   190
      }
moel@371
   191
      set {
moel@371
   192
        if (genericNotifyIcon != null)
moel@371
   193
          genericNotifyIcon.BalloonTipText = value;
moel@371
   194
        else
moel@371
   195
          windowsNotifyIcon.BalloonTipText = value;
moel@371
   196
      }
moel@371
   197
    }
moel@371
   198
moel@371
   199
    public ToolTipIcon BalloonTipIcon {
moel@371
   200
      get {
moel@371
   201
        if (genericNotifyIcon != null)
moel@371
   202
          return genericNotifyIcon.BalloonTipIcon;
moel@371
   203
        else
moel@371
   204
          return windowsNotifyIcon.BalloonTipIcon;
moel@371
   205
      }
moel@371
   206
      set {
moel@371
   207
        if (genericNotifyIcon != null)
moel@371
   208
          genericNotifyIcon.BalloonTipIcon = value;
moel@371
   209
        else
moel@371
   210
          windowsNotifyIcon.BalloonTipIcon = value;
moel@371
   211
      }
moel@371
   212
    }
moel@371
   213
moel@371
   214
    public string BalloonTipTitle {
moel@371
   215
      get {
moel@371
   216
        if (genericNotifyIcon != null)
moel@371
   217
          return genericNotifyIcon.BalloonTipTitle;
moel@371
   218
        else
moel@371
   219
          return windowsNotifyIcon.BalloonTipTitle;
moel@371
   220
      }
moel@371
   221
      set {
moel@371
   222
        if (genericNotifyIcon != null)
moel@371
   223
          genericNotifyIcon.BalloonTipTitle = value;
moel@371
   224
        else
moel@371
   225
          windowsNotifyIcon.BalloonTipTitle = value;
moel@371
   226
      }
moel@371
   227
    }
moel@371
   228
moel@371
   229
    public ContextMenu ContextMenu {
moel@371
   230
      get {
moel@371
   231
        if (genericNotifyIcon != null)
moel@371
   232
          return genericNotifyIcon.ContextMenu;
moel@371
   233
        else
moel@371
   234
          return windowsNotifyIcon.ContextMenu;
moel@371
   235
      }
moel@371
   236
      set {
moel@371
   237
        if (genericNotifyIcon != null)
moel@371
   238
          genericNotifyIcon.ContextMenu = value;
moel@371
   239
        else
moel@371
   240
          windowsNotifyIcon.ContextMenu = value;
moel@371
   241
      }
moel@371
   242
    }
moel@371
   243
moel@371
   244
    public ContextMenuStrip ContextMenuStrip {
moel@371
   245
      get {
moel@371
   246
        if (genericNotifyIcon != null)
moel@371
   247
          return genericNotifyIcon.ContextMenuStrip;
moel@371
   248
        else
moel@371
   249
          return windowsNotifyIcon.ContextMenuStrip;
moel@371
   250
      }
moel@371
   251
      set {
moel@371
   252
        if (genericNotifyIcon != null)
moel@371
   253
          genericNotifyIcon.ContextMenuStrip = value;
moel@371
   254
        else
moel@371
   255
          windowsNotifyIcon.ContextMenuStrip = value;
moel@371
   256
      }
moel@371
   257
    }
moel@371
   258
moel@363
   259
    public object Tag { get; set; }
moel@363
   260
moel@363
   261
    public Icon Icon {
moel@363
   262
      get {
moel@371
   263
        if (genericNotifyIcon != null)
moel@371
   264
          return genericNotifyIcon.Icon;
moel@371
   265
        else
moel@371
   266
          return windowsNotifyIcon.Icon;
moel@363
   267
      }
moel@363
   268
      set {
moel@371
   269
        if (genericNotifyIcon != null)
moel@371
   270
          genericNotifyIcon.Icon = value;
moel@371
   271
        else
moel@371
   272
          windowsNotifyIcon.Icon = value;
moel@363
   273
      }
moel@363
   274
    }
moel@363
   275
moel@363
   276
    public string Text {
moel@363
   277
      get {
moel@371
   278
        if (genericNotifyIcon != null)
moel@371
   279
          return genericNotifyIcon.Text;
moel@371
   280
        else
moel@371
   281
          return windowsNotifyIcon.Text;
moel@363
   282
      }
moel@363
   283
      set {
moel@371
   284
        if (genericNotifyIcon != null)
moel@371
   285
          genericNotifyIcon.Text = value;
moel@371
   286
        else
moel@371
   287
          windowsNotifyIcon.Text = value;
moel@363
   288
      }
moel@363
   289
    }
moel@363
   290
moel@363
   291
    public bool Visible {
moel@363
   292
      get {
moel@371
   293
        if (genericNotifyIcon != null)
moel@371
   294
          return genericNotifyIcon.Visible;
moel@371
   295
        else
moel@371
   296
          return windowsNotifyIcon.Visible;
moel@363
   297
      }
moel@363
   298
      set {
moel@371
   299
        if (genericNotifyIcon != null)
moel@371
   300
          genericNotifyIcon.Visible = value;
moel@371
   301
        else
moel@371
   302
          windowsNotifyIcon.Visible = value;
moel@363
   303
      }
moel@363
   304
    }
moel@363
   305
moel@371
   306
    public void Dispose() {
moel@371
   307
      if (genericNotifyIcon != null)
moel@371
   308
        genericNotifyIcon.Dispose();
moel@371
   309
      else
moel@371
   310
        windowsNotifyIcon.Dispose();
moel@363
   311
    }
moel@363
   312
moel@363
   313
    public void ShowBalloonTip(int timeout) {
moel@363
   314
      ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
moel@363
   315
    }
moel@363
   316
moel@363
   317
    public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
moel@371
   318
      ToolTipIcon tipIcon) {
moel@371
   319
      if (genericNotifyIcon != null)
moel@371
   320
        genericNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
moel@371
   321
      else
moel@371
   322
        windowsNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
moel@371
   323
    }
moel@371
   324
    
moel@371
   325
    private class NotifyIconWindowsImplementation : Component {
moel@363
   326
moel@371
   327
      private static int nextId = 0;
moel@363
   328
moel@371
   329
      private object syncObj = new object();
moel@371
   330
      private Icon icon;
moel@371
   331
      private string text = "";
moel@371
   332
      private int id;
moel@371
   333
      private bool created;
moel@371
   334
      private NotifyIconNativeWindow window;
moel@371
   335
      private bool doubleClickDown;
moel@371
   336
      private bool visible;
moel@371
   337
      private MethodInfo commandDispatch;
moel@363
   338
moel@371
   339
      public event EventHandler BalloonTipClicked;
moel@371
   340
      public event EventHandler BalloonTipClosed;
moel@371
   341
      public event EventHandler BalloonTipShown;
moel@371
   342
      public event EventHandler Click;
moel@371
   343
      public event EventHandler DoubleClick;
moel@371
   344
      public event MouseEventHandler MouseClick;
moel@371
   345
      public event MouseEventHandler MouseDoubleClick;
moel@371
   346
      public event MouseEventHandler MouseDown;
moel@371
   347
      public event MouseEventHandler MouseMove;
moel@371
   348
      public event MouseEventHandler MouseUp;
moel@363
   349
moel@371
   350
      public string BalloonTipText { get; set; }
moel@371
   351
      public ToolTipIcon BalloonTipIcon { get; set; }
moel@371
   352
      public string BalloonTipTitle { get; set; }
moel@371
   353
      public ContextMenu ContextMenu { get; set; }
moel@371
   354
      public ContextMenuStrip ContextMenuStrip { get; set; }
moel@371
   355
      public object Tag { get; set; }
moel@363
   356
moel@371
   357
      public Icon Icon {
moel@371
   358
        get {
moel@371
   359
          return icon;
moel@363
   360
        }
moel@371
   361
        set {
moel@371
   362
          if (icon != value) {
moel@371
   363
            icon = value;
moel@371
   364
            UpdateNotifyIcon(visible);
moel@363
   365
          }
moel@363
   366
        }
moel@363
   367
      }
moel@363
   368
moel@371
   369
      public string Text {
moel@371
   370
        get {
moel@371
   371
          return text;
moel@371
   372
        }
moel@371
   373
        set {
moel@371
   374
          if (value == null)
moel@371
   375
            value = "";
moel@363
   376
moel@371
   377
          if (value.Length > 63)
moel@371
   378
            throw new ArgumentOutOfRangeException();
moel@363
   379
moel@371
   380
          if (!value.Equals(text)) {
moel@371
   381
            text = value;
moel@371
   382
moel@371
   383
            if (visible)
moel@371
   384
              UpdateNotifyIcon(visible);
moel@371
   385
          }
moel@371
   386
        }
moel@363
   387
      }
moel@363
   388
moel@371
   389
      public bool Visible {
moel@371
   390
        get {
moel@371
   391
          return visible;
moel@371
   392
        }
moel@371
   393
        set {
moel@371
   394
          if (visible != value) {
moel@371
   395
            visible = value;
moel@371
   396
            UpdateNotifyIcon(visible);
moel@363
   397
          }
moel@371
   398
        }
moel@363
   399
      }
moel@363
   400
moel@371
   401
      public NotifyIconWindowsImplementation() {
moel@371
   402
        BalloonTipText = "";
moel@371
   403
        BalloonTipTitle = "";
moel@371
   404
moel@371
   405
        commandDispatch = typeof(Form).Assembly.
moel@371
   406
          GetType("System.Windows.Forms.Command").GetMethod("DispatchID",
moel@371
   407
          BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
moel@371
   408
          null, new Type[] { typeof(int) }, null);
moel@371
   409
moel@371
   410
        id = ++NotifyIconWindowsImplementation.nextId;
moel@371
   411
        window = new NotifyIconNativeWindow(this);
moel@363
   412
        UpdateNotifyIcon(visible);
moel@363
   413
      }
moel@363
   414
moel@371
   415
      protected override void Dispose(bool disposing) {
moel@371
   416
        if (disposing) {
moel@371
   417
          if (window != null) {
moel@371
   418
            icon = null;
moel@371
   419
            text = "";
moel@371
   420
            UpdateNotifyIcon(false);
moel@371
   421
            window.DestroyHandle();
moel@371
   422
            window = null;
moel@371
   423
            ContextMenu = null;
moel@371
   424
            ContextMenuStrip = null;
moel@371
   425
          }
moel@371
   426
        } else {
moel@371
   427
          if (window != null && window.Handle != IntPtr.Zero) {
moel@371
   428
            NativeMethods.PostMessage(
moel@371
   429
              new HandleRef(window, window.Handle), WM_CLOSE, 0, 0);
moel@371
   430
            window.ReleaseHandle();
moel@371
   431
          }
moel@371
   432
        }
moel@371
   433
        base.Dispose(disposing);
moel@363
   434
      }
moel@363
   435
moel@371
   436
      public void ShowBalloonTip(int timeout) {
moel@371
   437
        ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
moel@363
   438
      }
moel@363
   439
moel@371
   440
      public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
moel@371
   441
        ToolTipIcon tipIcon) {
moel@371
   442
        if (timeout < 0)
moel@371
   443
          throw new ArgumentOutOfRangeException("timeout");
moel@371
   444
moel@371
   445
        if (string.IsNullOrEmpty(tipText))
moel@371
   446
          throw new ArgumentException("tipText");
moel@371
   447
moel@371
   448
        if (DesignMode)
moel@371
   449
          return;
moel@371
   450
moel@371
   451
        if (created) {
moel@371
   452
          NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
moel@371
   453
          if (window.Handle == IntPtr.Zero)
moel@371
   454
            window.CreateHandle(new CreateParams());
moel@371
   455
moel@371
   456
          data.Window = window.Handle;
moel@371
   457
          data.ID = id;
moel@371
   458
          data.Flags = NativeMethods.NotifyIconDataFlags.Info;
moel@371
   459
          data.TimeoutOrVersion = timeout;
moel@371
   460
          data.InfoTitle = tipTitle;
moel@371
   461
          data.Info = tipText;
moel@371
   462
          data.InfoFlags = (int)tipIcon;
moel@371
   463
moel@371
   464
          NativeMethods.Shell_NotifyIcon(
moel@371
   465
            NativeMethods.NotifyIconMessage.Modify, data);
moel@363
   466
        }
moel@363
   467
      }
moel@363
   468
moel@371
   469
      private void ShowContextMenu() {
moel@371
   470
        if (ContextMenu == null && ContextMenuStrip == null)
moel@371
   471
          return;
moel@371
   472
moel@371
   473
        NativeMethods.Point p = new NativeMethods.Point();
moel@371
   474
        NativeMethods.GetCursorPos(ref p);
moel@371
   475
        NativeMethods.SetForegroundWindow(
moel@371
   476
          new HandleRef(window, window.Handle));
moel@371
   477
moel@371
   478
        if (ContextMenu != null) {
moel@371
   479
          ContextMenu.GetType().InvokeMember("OnPopup",
moel@371
   480
            BindingFlags.NonPublic | BindingFlags.InvokeMethod |
moel@371
   481
            BindingFlags.Instance, null, ContextMenu,
moel@371
   482
            new Object[] { System.EventArgs.Empty });
moel@371
   483
moel@371
   484
          NativeMethods.TrackPopupMenuEx(
moel@371
   485
            new HandleRef(ContextMenu, ContextMenu.Handle), 72,
moel@371
   486
            p.x, p.y, new HandleRef(window, window.Handle),
moel@371
   487
            IntPtr.Zero);
moel@371
   488
moel@371
   489
          NativeMethods.PostMessage(
moel@371
   490
            new HandleRef(window, window.Handle), WM_NULL, 0, 0);
moel@371
   491
          return;
moel@371
   492
        }
moel@371
   493
moel@371
   494
        if (ContextMenuStrip != null)
moel@371
   495
          ContextMenuStrip.GetType().InvokeMember("ShowInTaskbar",
moel@371
   496
            BindingFlags.NonPublic | BindingFlags.InvokeMethod |
moel@371
   497
            BindingFlags.Instance, null, ContextMenuStrip,
moel@371
   498
            new Object[] { p.x, p.y });
moel@363
   499
      }
moel@363
   500
moel@371
   501
      private void UpdateNotifyIcon(bool showNotifyIcon) {
moel@371
   502
        if (DesignMode)
moel@371
   503
          return;
moel@363
   504
moel@371
   505
        lock (syncObj) {
moel@371
   506
          window.LockReference(showNotifyIcon);
moel@363
   507
moel@371
   508
          NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
moel@371
   509
          data.CallbackMessage = WM_TRAYMOUSEMESSAGE;
moel@371
   510
          data.Flags = NativeMethods.NotifyIconDataFlags.Message;
moel@363
   511
moel@371
   512
          if (showNotifyIcon && window.Handle == IntPtr.Zero)
moel@371
   513
            window.CreateHandle(new CreateParams());
moel@363
   514
moel@371
   515
          data.Window = window.Handle;
moel@371
   516
          data.ID = id;
moel@363
   517
moel@371
   518
          if (icon != null) {
moel@371
   519
            data.Flags |= NativeMethods.NotifyIconDataFlags.Icon;
moel@371
   520
            data.Icon = icon.Handle;
moel@371
   521
          }
moel@363
   522
moel@371
   523
          data.Flags |= NativeMethods.NotifyIconDataFlags.Tip;
moel@371
   524
          data.Tip = text;
moel@371
   525
moel@371
   526
          if (showNotifyIcon && icon != null) {
moel@371
   527
            if (!created) {
moel@371
   528
              int i = 0;
moel@371
   529
              do {
moel@371
   530
                created = NativeMethods.Shell_NotifyIcon(
moel@371
   531
                  NativeMethods.NotifyIconMessage.Add, data);
moel@371
   532
                if (!created) {
moel@371
   533
                  System.Threading.Thread.Sleep(200);
moel@371
   534
                  i++;
moel@371
   535
                }
moel@371
   536
              } while (!created && i < 40);
moel@371
   537
            } else {
moel@371
   538
              NativeMethods.Shell_NotifyIcon(
moel@371
   539
                NativeMethods.NotifyIconMessage.Modify, data);
moel@371
   540
            }
moel@371
   541
          } else {
moel@371
   542
            if (created) {
moel@371
   543
              int i = 0;
moel@371
   544
              bool deleted = false;
moel@371
   545
              do {
moel@371
   546
                deleted = NativeMethods.Shell_NotifyIcon(
moel@371
   547
                  NativeMethods.NotifyIconMessage.Delete, data);
moel@371
   548
                if (!deleted) {
moel@371
   549
                  System.Threading.Thread.Sleep(200);
moel@371
   550
                  i++;
moel@371
   551
                }
moel@371
   552
              } while (!deleted && i < 40);
moel@371
   553
              created = false;
moel@371
   554
            }
moel@371
   555
          }
moel@371
   556
        }
moel@363
   557
      }
moel@363
   558
moel@371
   559
      private void ProcessMouseDown(ref Message message, MouseButtons button,
moel@371
   560
        bool doubleClick) {
moel@371
   561
        if (doubleClick) {
moel@371
   562
          if (DoubleClick != null)
moel@371
   563
            DoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
moel@371
   564
moel@371
   565
          if (MouseDoubleClick != null)
moel@371
   566
            MouseDoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
moel@371
   567
moel@371
   568
          doubleClickDown = true;
moel@371
   569
        }
moel@371
   570
moel@371
   571
        if (MouseDown != null)
moel@371
   572
          MouseDown(this,
moel@371
   573
            new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0));
moel@363
   574
      }
moel@363
   575
moel@371
   576
      private void ProcessMouseUp(ref Message message, MouseButtons button) {
moel@371
   577
        if (MouseUp != null)
moel@371
   578
          MouseUp(this, new MouseEventArgs(button, 0, 0, 0, 0));
moel@371
   579
moel@371
   580
        if (!doubleClickDown) {
moel@371
   581
          if (Click != null)
moel@371
   582
            Click(this, new MouseEventArgs(button, 0, 0, 0, 0));
moel@371
   583
moel@371
   584
          if (MouseClick != null)
moel@371
   585
            MouseClick(this, new MouseEventArgs(button, 0, 0, 0, 0));
moel@371
   586
        }
moel@371
   587
        doubleClickDown = false;
moel@363
   588
      }
moel@363
   589
moel@371
   590
      private void ProcessInitMenuPopup(ref Message message) {
moel@371
   591
        if (ContextMenu != null &&
moel@371
   592
          (bool)ContextMenu.GetType().InvokeMember("ProcessInitMenuPopup",
moel@371
   593
            BindingFlags.NonPublic | BindingFlags.InvokeMethod |
moel@371
   594
            BindingFlags.Instance, null, ContextMenu,
moel@371
   595
            new Object[] { message.WParam })) {
moel@371
   596
          return;
moel@371
   597
        }
moel@371
   598
        window.DefWndProc(ref message);
moel@363
   599
      }
moel@363
   600
moel@371
   601
      private void WndProc(ref Message message) {
moel@371
   602
        switch (message.Msg) {
moel@371
   603
          case WM_DESTROY:
moel@371
   604
            UpdateNotifyIcon(false);
moel@371
   605
            return;
moel@371
   606
          case WM_COMMAND:
moel@371
   607
            if (message.LParam != IntPtr.Zero) {
moel@371
   608
              window.DefWndProc(ref message);
moel@371
   609
              return;
moel@371
   610
            }
moel@371
   611
            commandDispatch.Invoke(null, new object[] { 
moel@371
   612
            message.WParam.ToInt32() & 0xFFFF });
moel@371
   613
            return;
moel@371
   614
          case WM_INITMENUPOPUP:
moel@371
   615
            ProcessInitMenuPopup(ref message);
moel@371
   616
            return;
moel@371
   617
          case WM_TRAYMOUSEMESSAGE:
moel@371
   618
            switch ((int)message.LParam) {
moel@371
   619
              case WM_MOUSEMOVE:
moel@371
   620
                if (MouseMove != null)
moel@371
   621
                  MouseMove(this,
moel@371
   622
                    new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0));
moel@371
   623
                return;
moel@371
   624
              case WM_LBUTTONDOWN:
moel@371
   625
                ProcessMouseDown(ref message, MouseButtons.Left, false);
moel@371
   626
                return;
moel@371
   627
              case WM_LBUTTONUP:
moel@371
   628
                ProcessMouseUp(ref message, MouseButtons.Left);
moel@371
   629
                return;
moel@371
   630
              case WM_LBUTTONDBLCLK:
moel@371
   631
                ProcessMouseDown(ref message, MouseButtons.Left, true);
moel@371
   632
                return;
moel@371
   633
              case WM_RBUTTONDOWN:
moel@371
   634
                ProcessMouseDown(ref message, MouseButtons.Right, false);
moel@371
   635
                return;
moel@371
   636
              case WM_RBUTTONUP:
moel@371
   637
                if (ContextMenu != null || ContextMenuStrip != null)
moel@371
   638
                  ShowContextMenu();
moel@371
   639
                ProcessMouseUp(ref message, MouseButtons.Right);
moel@371
   640
                return;
moel@371
   641
              case WM_RBUTTONDBLCLK:
moel@371
   642
                ProcessMouseDown(ref message, MouseButtons.Right, true);
moel@371
   643
                return;
moel@371
   644
              case WM_MBUTTONDOWN:
moel@371
   645
                ProcessMouseDown(ref message, MouseButtons.Middle, false);
moel@371
   646
                return;
moel@371
   647
              case WM_MBUTTONUP:
moel@371
   648
                ProcessMouseUp(ref message, MouseButtons.Middle);
moel@371
   649
                return;
moel@371
   650
              case WM_MBUTTONDBLCLK:
moel@371
   651
                ProcessMouseDown(ref message, MouseButtons.Middle, true);
moel@371
   652
                return;
moel@371
   653
              case NIN_BALLOONSHOW:
moel@371
   654
                if (BalloonTipShown != null)
moel@371
   655
                  BalloonTipShown(this, EventArgs.Empty);
moel@371
   656
                return;
moel@371
   657
              case NIN_BALLOONHIDE:
moel@371
   658
              case NIN_BALLOONTIMEOUT:
moel@371
   659
                if (BalloonTipClosed != null)
moel@371
   660
                  BalloonTipClosed(this, EventArgs.Empty);
moel@371
   661
                return;
moel@371
   662
              case NIN_BALLOONUSERCLICK:
moel@371
   663
                if (BalloonTipClicked != null)
moel@371
   664
                  BalloonTipClicked(this, EventArgs.Empty);
moel@371
   665
                return;
moel@371
   666
              default:
moel@371
   667
                return;
moel@371
   668
            }
moel@371
   669
        }
moel@363
   670
moel@371
   671
        if (message.Msg == NotifyIconWindowsImplementation.WM_TASKBARCREATED) {
moel@371
   672
          lock (syncObj) {
moel@371
   673
            created = false;
moel@371
   674
          }
moel@371
   675
          UpdateNotifyIcon(visible);
moel@371
   676
        }
moel@371
   677
moel@371
   678
        window.DefWndProc(ref message);
moel@371
   679
      }
moel@371
   680
moel@371
   681
      private class NotifyIconNativeWindow : NativeWindow {
moel@371
   682
        private NotifyIconWindowsImplementation reference;
moel@371
   683
        private GCHandle referenceHandle;
moel@371
   684
moel@371
   685
        internal NotifyIconNativeWindow(NotifyIconWindowsImplementation component) {
moel@371
   686
          this.reference = component;
moel@371
   687
        }
moel@371
   688
moel@371
   689
        ~NotifyIconNativeWindow() {
moel@371
   690
          if (base.Handle != IntPtr.Zero)
moel@371
   691
            NativeMethods.PostMessage(
moel@371
   692
              new HandleRef(this, base.Handle), WM_CLOSE, 0, 0);
moel@371
   693
        }
moel@371
   694
moel@371
   695
        public void LockReference(bool locked) {
moel@371
   696
          if (locked) {
moel@371
   697
            if (!referenceHandle.IsAllocated) {
moel@371
   698
              referenceHandle = GCHandle.Alloc(reference, GCHandleType.Normal);
moel@371
   699
              return;
moel@371
   700
            }
moel@371
   701
          } else {
moel@371
   702
            if (referenceHandle.IsAllocated)
moel@371
   703
              referenceHandle.Free();
moel@371
   704
          }
moel@371
   705
        }
moel@371
   706
moel@371
   707
        protected override void OnThreadException(Exception e) {
moel@371
   708
          Application.OnThreadException(e);
moel@371
   709
        }
moel@371
   710
moel@371
   711
        protected override void WndProc(ref Message m) {
moel@371
   712
          reference.WndProc(ref m);
moel@371
   713
        }
moel@371
   714
      }
moel@371
   715
moel@371
   716
      private const int WM_NULL = 0x00;
moel@371
   717
      private const int WM_DESTROY = 0x02;
moel@371
   718
      private const int WM_CLOSE = 0x10;
moel@371
   719
      private const int WM_COMMAND = 0x111;
moel@371
   720
      private const int WM_INITMENUPOPUP = 0x117;
moel@371
   721
      private const int WM_MOUSEMOVE = 0x200;
moel@371
   722
      private const int WM_LBUTTONDOWN = 0x201;
moel@371
   723
      private const int WM_LBUTTONUP = 0x202;
moel@371
   724
      private const int WM_LBUTTONDBLCLK = 0x203;
moel@371
   725
      private const int WM_RBUTTONDOWN = 0x204;
moel@371
   726
      private const int WM_RBUTTONUP = 0x205;
moel@371
   727
      private const int WM_RBUTTONDBLCLK = 0x206;
moel@371
   728
      private const int WM_MBUTTONDOWN = 0x207;
moel@371
   729
      private const int WM_MBUTTONUP = 0x208;
moel@371
   730
      private const int WM_MBUTTONDBLCLK = 0x209;
moel@371
   731
      private const int WM_TRAYMOUSEMESSAGE = 0x800;
moel@371
   732
moel@371
   733
      private const int NIN_BALLOONSHOW = 0x402;
moel@371
   734
      private const int NIN_BALLOONHIDE = 0x403;
moel@371
   735
      private const int NIN_BALLOONTIMEOUT = 0x404;
moel@371
   736
      private const int NIN_BALLOONUSERCLICK = 0x405;
moel@371
   737
moel@371
   738
      private static int WM_TASKBARCREATED =
moel@371
   739
        NativeMethods.RegisterWindowMessage("TaskbarCreated");
moel@371
   740
moel@371
   741
      private static class NativeMethods {
moel@371
   742
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
moel@371
   743
        public static extern IntPtr PostMessage(HandleRef hwnd, int msg,
moel@371
   744
          int wparam, int lparam);
moel@371
   745
moel@371
   746
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
moel@371
   747
        public static extern int RegisterWindowMessage(string msg);
moel@371
   748
moel@371
   749
        [Flags]
moel@371
   750
        public enum NotifyIconDataFlags : int {
moel@371
   751
          Message = 0x1,
moel@371
   752
          Icon = 0x2,
moel@371
   753
          Tip = 0x4,
moel@371
   754
          State = 0x8,
moel@371
   755
          Info = 0x10
moel@371
   756
        }
moel@371
   757
moel@371
   758
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
moel@371
   759
        public class NotifyIconData {
moel@371
   760
          private int Size = Marshal.SizeOf(typeof(NotifyIconData));
moel@371
   761
          public IntPtr Window;
moel@371
   762
          public int ID;
moel@371
   763
          public NotifyIconDataFlags Flags;
moel@371
   764
          public int CallbackMessage;
moel@371
   765
          public IntPtr Icon;
moel@371
   766
          [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
moel@371
   767
          public string Tip;
moel@371
   768
          public int State;
moel@371
   769
          public int StateMask;
moel@371
   770
          [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
moel@371
   771
          public string Info;
moel@371
   772
          public int TimeoutOrVersion;
moel@371
   773
          [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
moel@371
   774
          public string InfoTitle;
moel@371
   775
          public int InfoFlags;
moel@371
   776
        }
moel@371
   777
moel@371
   778
        public enum NotifyIconMessage : int {
moel@371
   779
          Add = 0x0,
moel@371
   780
          Modify = 0x1,
moel@371
   781
          Delete = 0x2
moel@371
   782
        }
moel@371
   783
moel@371
   784
        [DllImport("shell32.dll", CharSet = CharSet.Auto)]
moel@371
   785
        [return: MarshalAs(UnmanagedType.Bool)]
moel@371
   786
        public static extern bool Shell_NotifyIcon(NotifyIconMessage message,
moel@371
   787
          NotifyIconData pnid);
moel@371
   788
moel@371
   789
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
moel@371
   790
        public static extern bool TrackPopupMenuEx(HandleRef hmenu, int fuFlags,
moel@371
   791
          int x, int y, HandleRef hwnd, IntPtr tpm);
moel@371
   792
moel@371
   793
        [StructLayout(LayoutKind.Sequential)]
moel@371
   794
        public struct Point {
moel@371
   795
          public int x;
moel@371
   796
          public int y;
moel@371
   797
        }
moel@371
   798
moel@371
   799
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
moel@371
   800
        public static extern bool GetCursorPos(ref Point point);
moel@371
   801
moel@371
   802
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
moel@371
   803
        public static extern bool SetForegroundWindow(HandleRef hWnd);
moel@371
   804
      }
moel@363
   805
    }
moel@363
   806
  }
moel@363
   807
}