Statistics
| Branch: | Revision:

root / trunk / NotifyIconWpf / TaskbarIcon.cs @ 025046f1

History | View | Annotate | Download (31 kB)

1 9bae55d1 Panagiotis Kanavos
// hardcodet.net NotifyIcon for WPF
2 9bae55d1 Panagiotis Kanavos
// Copyright (c) 2009 Philipp Sumi
3 9bae55d1 Panagiotis Kanavos
// Contact and Information: http://www.hardcodet.net
4 9bae55d1 Panagiotis Kanavos
//
5 9bae55d1 Panagiotis Kanavos
// This library is free software; you can redistribute it and/or
6 9bae55d1 Panagiotis Kanavos
// modify it under the terms of the Code Project Open License (CPOL);
7 9bae55d1 Panagiotis Kanavos
// either version 1.0 of the License, or (at your option) any later
8 9bae55d1 Panagiotis Kanavos
// version.
9 9bae55d1 Panagiotis Kanavos
// 
10 9bae55d1 Panagiotis Kanavos
// The above copyright notice and this permission notice shall be
11 9bae55d1 Panagiotis Kanavos
// included in all copies or substantial portions of the Software.
12 9bae55d1 Panagiotis Kanavos
// 
13 9bae55d1 Panagiotis Kanavos
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 9bae55d1 Panagiotis Kanavos
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15 9bae55d1 Panagiotis Kanavos
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 9bae55d1 Panagiotis Kanavos
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 9bae55d1 Panagiotis Kanavos
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 9bae55d1 Panagiotis Kanavos
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 9bae55d1 Panagiotis Kanavos
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 9bae55d1 Panagiotis Kanavos
// OTHER DEALINGS IN THE SOFTWARE.
21 9bae55d1 Panagiotis Kanavos
//
22 9bae55d1 Panagiotis Kanavos
// THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE
23 9bae55d1 Panagiotis Kanavos
24 9bae55d1 Panagiotis Kanavos
25 9bae55d1 Panagiotis Kanavos
using System;
26 9bae55d1 Panagiotis Kanavos
using System.ComponentModel;
27 9bae55d1 Panagiotis Kanavos
using System.Diagnostics;
28 9bae55d1 Panagiotis Kanavos
using System.Drawing;
29 9bae55d1 Panagiotis Kanavos
using System.Threading;
30 9bae55d1 Panagiotis Kanavos
using System.Windows;
31 9bae55d1 Panagiotis Kanavos
using System.Windows.Controls;
32 9bae55d1 Panagiotis Kanavos
using System.Windows.Controls.Primitives;
33 9bae55d1 Panagiotis Kanavos
using System.Windows.Interop;
34 9bae55d1 Panagiotis Kanavos
using System.Windows.Threading;
35 9bae55d1 Panagiotis Kanavos
using Hardcodet.Wpf.TaskbarNotification.Interop;
36 9bae55d1 Panagiotis Kanavos
using Point=Hardcodet.Wpf.TaskbarNotification.Interop.Point;
37 9bae55d1 Panagiotis Kanavos
38 9bae55d1 Panagiotis Kanavos
39 9bae55d1 Panagiotis Kanavos
40 9bae55d1 Panagiotis Kanavos
namespace Hardcodet.Wpf.TaskbarNotification
41 9bae55d1 Panagiotis Kanavos
{
42 9bae55d1 Panagiotis Kanavos
  /// <summary>
43 9bae55d1 Panagiotis Kanavos
  /// A WPF proxy to for a taskbar icon (NotifyIcon) that sits in the system's
44 9bae55d1 Panagiotis Kanavos
  /// taskbar notification area ("system tray").
45 9bae55d1 Panagiotis Kanavos
  /// </summary>
46 9bae55d1 Panagiotis Kanavos
  public partial class TaskbarIcon : FrameworkElement, IDisposable
47 9bae55d1 Panagiotis Kanavos
  {
48 9bae55d1 Panagiotis Kanavos
    #region Members
49 9bae55d1 Panagiotis Kanavos
50 9bae55d1 Panagiotis Kanavos
    /// <summary>
51 9bae55d1 Panagiotis Kanavos
    /// Represents the current icon data.
52 9bae55d1 Panagiotis Kanavos
    /// </summary>
53 9bae55d1 Panagiotis Kanavos
    private NotifyIconData iconData;
54 9bae55d1 Panagiotis Kanavos
55 9bae55d1 Panagiotis Kanavos
    /// <summary>
56 9bae55d1 Panagiotis Kanavos
    /// Receives messages from the taskbar icon.
57 9bae55d1 Panagiotis Kanavos
    /// </summary>
58 9bae55d1 Panagiotis Kanavos
    private readonly WindowMessageSink messageSink;
59 9bae55d1 Panagiotis Kanavos
60 9bae55d1 Panagiotis Kanavos
    /// <summary>
61 9bae55d1 Panagiotis Kanavos
    /// An action that is being invoked if the
62 9bae55d1 Panagiotis Kanavos
    /// <see cref="singleClickTimer"/> fires.
63 9bae55d1 Panagiotis Kanavos
    /// </summary>
64 9bae55d1 Panagiotis Kanavos
    private Action delayedTimerAction;
65 9bae55d1 Panagiotis Kanavos
66 9bae55d1 Panagiotis Kanavos
    /// <summary>
67 9bae55d1 Panagiotis Kanavos
    /// A timer that is used to differentiate between single
68 9bae55d1 Panagiotis Kanavos
    /// and double clicks.
69 9bae55d1 Panagiotis Kanavos
    /// </summary>
70 9bae55d1 Panagiotis Kanavos
    private readonly Timer singleClickTimer;
71 9bae55d1 Panagiotis Kanavos
72 9bae55d1 Panagiotis Kanavos
    /// <summary>
73 9bae55d1 Panagiotis Kanavos
    /// A timer that is used to close open balloon tooltips.
74 9bae55d1 Panagiotis Kanavos
    /// </summary>
75 9bae55d1 Panagiotis Kanavos
    private readonly Timer balloonCloseTimer;
76 9bae55d1 Panagiotis Kanavos
77 9bae55d1 Panagiotis Kanavos
    /// <summary>
78 9bae55d1 Panagiotis Kanavos
    /// Indicates whether the taskbar icon has been created or not.
79 9bae55d1 Panagiotis Kanavos
    /// </summary>
80 9bae55d1 Panagiotis Kanavos
    public bool IsTaskbarIconCreated { get; private set; }
81 9bae55d1 Panagiotis Kanavos
82 9bae55d1 Panagiotis Kanavos
    /// <summary>
83 9bae55d1 Panagiotis Kanavos
    /// Indicates whether custom tooltips are supported, which depends
84 9bae55d1 Panagiotis Kanavos
    /// on the OS. Windows Vista or higher is required in order to
85 9bae55d1 Panagiotis Kanavos
    /// support this feature.
86 9bae55d1 Panagiotis Kanavos
    /// </summary>
87 9bae55d1 Panagiotis Kanavos
    public bool SupportsCustomToolTips
88 9bae55d1 Panagiotis Kanavos
    {
89 9bae55d1 Panagiotis Kanavos
      get { return messageSink.Version == NotifyIconVersion.Vista; }
90 9bae55d1 Panagiotis Kanavos
    }
91 9bae55d1 Panagiotis Kanavos
92 9bae55d1 Panagiotis Kanavos
93 9bae55d1 Panagiotis Kanavos
94 9bae55d1 Panagiotis Kanavos
    /// <summary>
95 9bae55d1 Panagiotis Kanavos
    /// Checks whether a non-tooltip popup is currently opened.
96 9bae55d1 Panagiotis Kanavos
    /// </summary>
97 9bae55d1 Panagiotis Kanavos
    private bool IsPopupOpen
98 9bae55d1 Panagiotis Kanavos
    {
99 9bae55d1 Panagiotis Kanavos
      get
100 9bae55d1 Panagiotis Kanavos
      {
101 9bae55d1 Panagiotis Kanavos
        var popup = TrayPopupResolved;
102 9bae55d1 Panagiotis Kanavos
        var menu = ContextMenu;
103 9bae55d1 Panagiotis Kanavos
        var balloon = CustomBalloon;
104 9bae55d1 Panagiotis Kanavos
105 9bae55d1 Panagiotis Kanavos
        return popup != null && popup.IsOpen ||
106 9bae55d1 Panagiotis Kanavos
               menu != null && menu.IsOpen ||
107 9bae55d1 Panagiotis Kanavos
               balloon != null && balloon.IsOpen;
108 9bae55d1 Panagiotis Kanavos
109 9bae55d1 Panagiotis Kanavos
      }
110 9bae55d1 Panagiotis Kanavos
    }
111 9bae55d1 Panagiotis Kanavos
112 9bae55d1 Panagiotis Kanavos
    #endregion
113 9bae55d1 Panagiotis Kanavos
114 9bae55d1 Panagiotis Kanavos
115 9bae55d1 Panagiotis Kanavos
    #region Construction
116 9bae55d1 Panagiotis Kanavos
117 9bae55d1 Panagiotis Kanavos
    /// <summary>
118 9bae55d1 Panagiotis Kanavos
    /// Inits the taskbar icon and registers a message listener
119 9bae55d1 Panagiotis Kanavos
    /// in order to receive events from the taskbar area.
120 9bae55d1 Panagiotis Kanavos
    /// </summary>
121 9bae55d1 Panagiotis Kanavos
    public TaskbarIcon()
122 9bae55d1 Panagiotis Kanavos
    {
123 9bae55d1 Panagiotis Kanavos
      //using dummy sink in design mode
124 9bae55d1 Panagiotis Kanavos
      messageSink = Util.IsDesignMode
125 9bae55d1 Panagiotis Kanavos
                        ? WindowMessageSink.CreateEmpty()
126 9bae55d1 Panagiotis Kanavos
                        : new WindowMessageSink(NotifyIconVersion.Win95);
127 9bae55d1 Panagiotis Kanavos
128 9bae55d1 Panagiotis Kanavos
      //init icon data structure
129 9bae55d1 Panagiotis Kanavos
      iconData = NotifyIconData.CreateDefault(messageSink.MessageWindowHandle);
130 9bae55d1 Panagiotis Kanavos
131 9bae55d1 Panagiotis Kanavos
      //create the taskbar icon
132 9bae55d1 Panagiotis Kanavos
      CreateTaskbarIcon();
133 9bae55d1 Panagiotis Kanavos
134 9bae55d1 Panagiotis Kanavos
      //register event listeners
135 9bae55d1 Panagiotis Kanavos
      messageSink.MouseEventReceived += OnMouseEvent;
136 9bae55d1 Panagiotis Kanavos
      messageSink.TaskbarCreated += OnTaskbarCreated;
137 9bae55d1 Panagiotis Kanavos
      messageSink.ChangeToolTipStateRequest += OnToolTipChange;
138 9bae55d1 Panagiotis Kanavos
      messageSink.BalloonToolTipChanged += OnBalloonToolTipChanged;
139 9bae55d1 Panagiotis Kanavos
140 9bae55d1 Panagiotis Kanavos
      //init single click / balloon timers
141 9bae55d1 Panagiotis Kanavos
      singleClickTimer = new Timer(DoSingleClickAction);
142 9bae55d1 Panagiotis Kanavos
      balloonCloseTimer = new Timer(CloseBalloonCallback);
143 9bae55d1 Panagiotis Kanavos
144 9bae55d1 Panagiotis Kanavos
      //register listener in order to get notified when the application closes
145 9bae55d1 Panagiotis Kanavos
      if (Application.Current != null) Application.Current.Exit += OnExit;
146 9bae55d1 Panagiotis Kanavos
    }
147 9bae55d1 Panagiotis Kanavos
148 9bae55d1 Panagiotis Kanavos
    #endregion
149 9bae55d1 Panagiotis Kanavos
150 9bae55d1 Panagiotis Kanavos
151 9bae55d1 Panagiotis Kanavos
    #region Custom Balloons
152 9bae55d1 Panagiotis Kanavos
153 9bae55d1 Panagiotis Kanavos
    /// <summary>
154 9bae55d1 Panagiotis Kanavos
    /// Shows a custom control as a tooltip in the tray location.
155 9bae55d1 Panagiotis Kanavos
    /// </summary>
156 9bae55d1 Panagiotis Kanavos
    /// <param name="balloon"></param>
157 9bae55d1 Panagiotis Kanavos
    /// <param name="animation">An optional animation for the popup.</param>
158 9bae55d1 Panagiotis Kanavos
    /// <param name="timeout">The time after which the popup is being closed.
159 9bae55d1 Panagiotis Kanavos
    /// Submit null in order to keep the balloon open inde
160 9bae55d1 Panagiotis Kanavos
    /// </param>
161 9bae55d1 Panagiotis Kanavos
    /// <exception cref="ArgumentNullException">If <paramref name="balloon"/>
162 9bae55d1 Panagiotis Kanavos
    /// is a null reference.</exception>
163 9bae55d1 Panagiotis Kanavos
    public void ShowCustomBalloon(UIElement balloon, PopupAnimation animation, int? timeout)
164 9bae55d1 Panagiotis Kanavos
    {
165 9bae55d1 Panagiotis Kanavos
      Dispatcher dispatcher = this.GetDispatcher();
166 9bae55d1 Panagiotis Kanavos
      if (!dispatcher.CheckAccess())
167 9bae55d1 Panagiotis Kanavos
      {
168 9bae55d1 Panagiotis Kanavos
        var action = new Action(() => ShowCustomBalloon(balloon, animation, timeout));
169 9bae55d1 Panagiotis Kanavos
        dispatcher.Invoke(DispatcherPriority.Normal, action);
170 9bae55d1 Panagiotis Kanavos
        return;
171 9bae55d1 Panagiotis Kanavos
      }
172 9bae55d1 Panagiotis Kanavos
173 9bae55d1 Panagiotis Kanavos
      if (balloon == null) throw new ArgumentNullException("balloon");
174 9bae55d1 Panagiotis Kanavos
      if (timeout.HasValue && timeout < 500)
175 9bae55d1 Panagiotis Kanavos
      {
176 9bae55d1 Panagiotis Kanavos
        string msg = "Invalid timeout of {0} milliseconds. Timeout must be at least 500 ms";
177 9bae55d1 Panagiotis Kanavos
        msg = String.Format(msg, timeout); 
178 9bae55d1 Panagiotis Kanavos
        throw new ArgumentOutOfRangeException("timeout", msg);
179 9bae55d1 Panagiotis Kanavos
      }
180 9bae55d1 Panagiotis Kanavos
181 9bae55d1 Panagiotis Kanavos
      EnsureNotDisposed();
182 9bae55d1 Panagiotis Kanavos
183 9bae55d1 Panagiotis Kanavos
      //make sure we don't have an open balloon
184 9bae55d1 Panagiotis Kanavos
      lock (this)
185 9bae55d1 Panagiotis Kanavos
      {
186 9bae55d1 Panagiotis Kanavos
        CloseBalloon();
187 9bae55d1 Panagiotis Kanavos
      }
188 9bae55d1 Panagiotis Kanavos
      
189 9bae55d1 Panagiotis Kanavos
      //create an invisible popup that hosts the UIElement
190 9bae55d1 Panagiotis Kanavos
      Popup popup = new Popup();
191 9bae55d1 Panagiotis Kanavos
      popup.AllowsTransparency = true;
192 9bae55d1 Panagiotis Kanavos
193 9bae55d1 Panagiotis Kanavos
      //provide the popup with the taskbar icon's data context
194 9bae55d1 Panagiotis Kanavos
      UpdateDataContext(popup, null, DataContext);
195 9bae55d1 Panagiotis Kanavos
196 9bae55d1 Panagiotis Kanavos
      //don't animate by default - devs can use attached
197 9bae55d1 Panagiotis Kanavos
      //events or override
198 9bae55d1 Panagiotis Kanavos
      popup.PopupAnimation = animation;
199 9bae55d1 Panagiotis Kanavos
200 9bae55d1 Panagiotis Kanavos
      popup.Child = balloon;
201 9bae55d1 Panagiotis Kanavos
202 9bae55d1 Panagiotis Kanavos
      //don't set the PlacementTarget as it causes the popup to become hidden if the
203 9bae55d1 Panagiotis Kanavos
      //TaskbarIcon's parent is hidden, too...
204 9bae55d1 Panagiotis Kanavos
      //popup.PlacementTarget = this;
205 9bae55d1 Panagiotis Kanavos
      
206 9bae55d1 Panagiotis Kanavos
      popup.Placement = PlacementMode.AbsolutePoint;
207 9bae55d1 Panagiotis Kanavos
      popup.StaysOpen = true;
208 9bae55d1 Panagiotis Kanavos
209 9bae55d1 Panagiotis Kanavos
      Point position = TrayInfo.GetTrayLocation();
210 9bae55d1 Panagiotis Kanavos
      popup.HorizontalOffset = position.X -1;
211 9bae55d1 Panagiotis Kanavos
      popup.VerticalOffset = position.Y -1;
212 9bae55d1 Panagiotis Kanavos
213 9bae55d1 Panagiotis Kanavos
      //store reference
214 9bae55d1 Panagiotis Kanavos
      lock (this)
215 9bae55d1 Panagiotis Kanavos
      {
216 9bae55d1 Panagiotis Kanavos
        SetCustomBalloon(popup);
217 9bae55d1 Panagiotis Kanavos
      }
218 9bae55d1 Panagiotis Kanavos
219 9bae55d1 Panagiotis Kanavos
      //assign this instance as an attached property
220 9bae55d1 Panagiotis Kanavos
      SetParentTaskbarIcon(balloon, this);
221 9bae55d1 Panagiotis Kanavos
222 9bae55d1 Panagiotis Kanavos
      //fire attached event
223 9bae55d1 Panagiotis Kanavos
      RaiseBalloonShowingEvent(balloon, this);
224 9bae55d1 Panagiotis Kanavos
225 9bae55d1 Panagiotis Kanavos
      //display item
226 9bae55d1 Panagiotis Kanavos
      popup.IsOpen = true;
227 9bae55d1 Panagiotis Kanavos
228 9bae55d1 Panagiotis Kanavos
      if (timeout.HasValue)
229 9bae55d1 Panagiotis Kanavos
      {
230 9bae55d1 Panagiotis Kanavos
        //register timer to close the popup
231 9bae55d1 Panagiotis Kanavos
        balloonCloseTimer.Change(timeout.Value, Timeout.Infinite);
232 9bae55d1 Panagiotis Kanavos
      }
233 9bae55d1 Panagiotis Kanavos
    }
234 9bae55d1 Panagiotis Kanavos
235 9bae55d1 Panagiotis Kanavos
236 9bae55d1 Panagiotis Kanavos
    /// <summary>
237 9bae55d1 Panagiotis Kanavos
    /// Resets the closing timeout, which effectively
238 9bae55d1 Panagiotis Kanavos
    /// keeps a displayed balloon message open until
239 9bae55d1 Panagiotis Kanavos
    /// it is either closed programmatically through
240 9bae55d1 Panagiotis Kanavos
    /// <see cref="CloseBalloon"/> or due to a new
241 9bae55d1 Panagiotis Kanavos
    /// message being displayed.
242 9bae55d1 Panagiotis Kanavos
    /// </summary>
243 9bae55d1 Panagiotis Kanavos
    public void ResetBalloonCloseTimer()
244 9bae55d1 Panagiotis Kanavos
    {
245 9bae55d1 Panagiotis Kanavos
      if (IsDisposed) return;
246 9bae55d1 Panagiotis Kanavos
247 9bae55d1 Panagiotis Kanavos
      lock (this)
248 9bae55d1 Panagiotis Kanavos
      {
249 9bae55d1 Panagiotis Kanavos
        //reset timer in any case
250 9bae55d1 Panagiotis Kanavos
        balloonCloseTimer.Change(Timeout.Infinite, Timeout.Infinite);
251 9bae55d1 Panagiotis Kanavos
      }
252 9bae55d1 Panagiotis Kanavos
    }
253 9bae55d1 Panagiotis Kanavos
254 9bae55d1 Panagiotis Kanavos
255 9bae55d1 Panagiotis Kanavos
    /// <summary>
256 9bae55d1 Panagiotis Kanavos
    /// Closes the current <see cref="CustomBalloon"/>, if the
257 9bae55d1 Panagiotis Kanavos
    /// property is set.
258 9bae55d1 Panagiotis Kanavos
    /// </summary>
259 9bae55d1 Panagiotis Kanavos
    public void CloseBalloon()
260 9bae55d1 Panagiotis Kanavos
    {
261 9bae55d1 Panagiotis Kanavos
      if (IsDisposed) return;
262 9bae55d1 Panagiotis Kanavos
263 9bae55d1 Panagiotis Kanavos
      Dispatcher dispatcher = this.GetDispatcher();
264 9bae55d1 Panagiotis Kanavos
      if (!dispatcher.CheckAccess())
265 9bae55d1 Panagiotis Kanavos
      {
266 9bae55d1 Panagiotis Kanavos
        Action action = CloseBalloon;
267 9bae55d1 Panagiotis Kanavos
        dispatcher.Invoke(DispatcherPriority.Normal, action);
268 9bae55d1 Panagiotis Kanavos
        return;
269 9bae55d1 Panagiotis Kanavos
      }
270 9bae55d1 Panagiotis Kanavos
271 9bae55d1 Panagiotis Kanavos
      lock (this)
272 9bae55d1 Panagiotis Kanavos
      {
273 9bae55d1 Panagiotis Kanavos
        //reset timer in any case
274 9bae55d1 Panagiotis Kanavos
        balloonCloseTimer.Change(Timeout.Infinite, Timeout.Infinite);
275 9bae55d1 Panagiotis Kanavos
276 9bae55d1 Panagiotis Kanavos
        //reset old popup, if we still have one
277 9bae55d1 Panagiotis Kanavos
        Popup popup = CustomBalloon;
278 9bae55d1 Panagiotis Kanavos
        if (popup != null)
279 9bae55d1 Panagiotis Kanavos
        {
280 9bae55d1 Panagiotis Kanavos
          UIElement element = popup.Child;
281 9bae55d1 Panagiotis Kanavos
282 9bae55d1 Panagiotis Kanavos
          //announce closing
283 9bae55d1 Panagiotis Kanavos
          RoutedEventArgs eventArgs = RaiseBalloonClosingEvent(element, this);
284 9bae55d1 Panagiotis Kanavos
          if (!eventArgs.Handled)
285 9bae55d1 Panagiotis Kanavos
          {
286 9bae55d1 Panagiotis Kanavos
            //if the event was handled, clear the reference to the popup,
287 9bae55d1 Panagiotis Kanavos
            //but don't close it - the handling code has to manage this stuff now
288 9bae55d1 Panagiotis Kanavos
289 9bae55d1 Panagiotis Kanavos
            //close the popup
290 9bae55d1 Panagiotis Kanavos
            popup.IsOpen = false;
291 9bae55d1 Panagiotis Kanavos
292 9bae55d1 Panagiotis Kanavos
            //reset attached property
293 9bae55d1 Panagiotis Kanavos
            if (element != null) SetParentTaskbarIcon(element, null);
294 9bae55d1 Panagiotis Kanavos
          }
295 9bae55d1 Panagiotis Kanavos
296 9bae55d1 Panagiotis Kanavos
          //remove custom balloon anyway
297 9bae55d1 Panagiotis Kanavos
          SetCustomBalloon(null);
298 9bae55d1 Panagiotis Kanavos
        }
299 9bae55d1 Panagiotis Kanavos
      }
300 9bae55d1 Panagiotis Kanavos
    }
301 9bae55d1 Panagiotis Kanavos
302 9bae55d1 Panagiotis Kanavos
303 9bae55d1 Panagiotis Kanavos
    /// <summary>
304 9bae55d1 Panagiotis Kanavos
    /// Timer-invoke event which closes the currently open balloon and
305 9bae55d1 Panagiotis Kanavos
    /// resets the <see cref="CustomBalloon"/> dependency property.
306 9bae55d1 Panagiotis Kanavos
    /// </summary>
307 9bae55d1 Panagiotis Kanavos
    private void CloseBalloonCallback(object state)
308 9bae55d1 Panagiotis Kanavos
    {
309 9bae55d1 Panagiotis Kanavos
      if (IsDisposed) return;
310 9bae55d1 Panagiotis Kanavos
311 9bae55d1 Panagiotis Kanavos
      //switch to UI thread
312 9bae55d1 Panagiotis Kanavos
      Action action = CloseBalloon;
313 9bae55d1 Panagiotis Kanavos
      this.GetDispatcher().Invoke(action);
314 9bae55d1 Panagiotis Kanavos
    }
315 9bae55d1 Panagiotis Kanavos
316 9bae55d1 Panagiotis Kanavos
    #endregion
317 9bae55d1 Panagiotis Kanavos
318 9bae55d1 Panagiotis Kanavos
    #region Process Incoming Mouse Events
319 9bae55d1 Panagiotis Kanavos
320 9bae55d1 Panagiotis Kanavos
    /// <summary>
321 9bae55d1 Panagiotis Kanavos
    /// Processes mouse events, which are bubbled
322 9bae55d1 Panagiotis Kanavos
    /// through the class' routed events, trigger
323 9bae55d1 Panagiotis Kanavos
    /// certain actions (e.g. show a popup), or
324 9bae55d1 Panagiotis Kanavos
    /// both.
325 9bae55d1 Panagiotis Kanavos
    /// </summary>
326 9bae55d1 Panagiotis Kanavos
    /// <param name="me">Event flag.</param>
327 9bae55d1 Panagiotis Kanavos
    private void OnMouseEvent(MouseEvent me)
328 9bae55d1 Panagiotis Kanavos
    {
329 9bae55d1 Panagiotis Kanavos
      if (IsDisposed) return;
330 9bae55d1 Panagiotis Kanavos
331 9bae55d1 Panagiotis Kanavos
      switch (me)
332 9bae55d1 Panagiotis Kanavos
      {
333 9bae55d1 Panagiotis Kanavos
        case MouseEvent.MouseMove:
334 9bae55d1 Panagiotis Kanavos
          RaiseTrayMouseMoveEvent();
335 9bae55d1 Panagiotis Kanavos
          //immediately return - there's nothing left to evaluate
336 9bae55d1 Panagiotis Kanavos
          return;
337 9bae55d1 Panagiotis Kanavos
        case MouseEvent.IconRightMouseDown:
338 9bae55d1 Panagiotis Kanavos
          RaiseTrayRightMouseDownEvent();
339 9bae55d1 Panagiotis Kanavos
          break;
340 9bae55d1 Panagiotis Kanavos
        case MouseEvent.IconLeftMouseDown:
341 9bae55d1 Panagiotis Kanavos
          RaiseTrayLeftMouseDownEvent();
342 9bae55d1 Panagiotis Kanavos
          break;
343 9bae55d1 Panagiotis Kanavos
        case MouseEvent.IconRightMouseUp:
344 9bae55d1 Panagiotis Kanavos
          RaiseTrayRightMouseUpEvent();
345 9bae55d1 Panagiotis Kanavos
          break;
346 9bae55d1 Panagiotis Kanavos
        case MouseEvent.IconLeftMouseUp:
347 9bae55d1 Panagiotis Kanavos
          RaiseTrayLeftMouseUpEvent();
348 9bae55d1 Panagiotis Kanavos
          break;
349 9bae55d1 Panagiotis Kanavos
        case MouseEvent.IconMiddleMouseDown:
350 9bae55d1 Panagiotis Kanavos
          RaiseTrayMiddleMouseDownEvent();
351 9bae55d1 Panagiotis Kanavos
          break;
352 9bae55d1 Panagiotis Kanavos
        case MouseEvent.IconMiddleMouseUp:
353 9bae55d1 Panagiotis Kanavos
          RaiseTrayMiddleMouseUpEvent();
354 9bae55d1 Panagiotis Kanavos
          break;
355 9bae55d1 Panagiotis Kanavos
        case MouseEvent.IconDoubleClick:
356 9bae55d1 Panagiotis Kanavos
          //cancel single click timer
357 9bae55d1 Panagiotis Kanavos
          singleClickTimer.Change(Timeout.Infinite, Timeout.Infinite);
358 9bae55d1 Panagiotis Kanavos
          //bubble event
359 9bae55d1 Panagiotis Kanavos
          RaiseTrayMouseDoubleClickEvent();
360 9bae55d1 Panagiotis Kanavos
          break;
361 9bae55d1 Panagiotis Kanavos
        case MouseEvent.BalloonToolTipClicked:
362 9bae55d1 Panagiotis Kanavos
          RaiseTrayBalloonTipClickedEvent();
363 9bae55d1 Panagiotis Kanavos
          break;
364 9bae55d1 Panagiotis Kanavos
        default:
365 9bae55d1 Panagiotis Kanavos
          throw new ArgumentOutOfRangeException("me", "Missing handler for mouse event flag: " + me);
366 9bae55d1 Panagiotis Kanavos
      }
367 9bae55d1 Panagiotis Kanavos
368 9bae55d1 Panagiotis Kanavos
369 9bae55d1 Panagiotis Kanavos
      //get mouse coordinates
370 9bae55d1 Panagiotis Kanavos
      Point cursorPosition = new Point();
371 9bae55d1 Panagiotis Kanavos
      WinApi.GetCursorPos(ref cursorPosition);
372 9bae55d1 Panagiotis Kanavos
373 9bae55d1 Panagiotis Kanavos
      bool isLeftClickCommandInvoked = false;
374 9bae55d1 Panagiotis Kanavos
      
375 9bae55d1 Panagiotis Kanavos
      //show popup, if requested
376 9bae55d1 Panagiotis Kanavos
      if (me.IsMatch(PopupActivation))
377 9bae55d1 Panagiotis Kanavos
      {
378 9bae55d1 Panagiotis Kanavos
        if (me == MouseEvent.IconLeftMouseUp)
379 9bae55d1 Panagiotis Kanavos
        {
380 9bae55d1 Panagiotis Kanavos
          //show popup once we are sure it's not a double click
381 9bae55d1 Panagiotis Kanavos
          delayedTimerAction = () =>
382 9bae55d1 Panagiotis Kanavos
                                 {
383 9bae55d1 Panagiotis Kanavos
                                   LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this);
384 9bae55d1 Panagiotis Kanavos
                                   ShowTrayPopup(cursorPosition);
385 9bae55d1 Panagiotis Kanavos
                                 };
386 9bae55d1 Panagiotis Kanavos
          singleClickTimer.Change(WinApi.GetDoubleClickTime(), Timeout.Infinite);
387 9bae55d1 Panagiotis Kanavos
          isLeftClickCommandInvoked = true;
388 9bae55d1 Panagiotis Kanavos
        }
389 9bae55d1 Panagiotis Kanavos
        else
390 9bae55d1 Panagiotis Kanavos
        {
391 9bae55d1 Panagiotis Kanavos
          //show popup immediately
392 9bae55d1 Panagiotis Kanavos
          ShowTrayPopup(cursorPosition);
393 9bae55d1 Panagiotis Kanavos
        }
394 9bae55d1 Panagiotis Kanavos
      }
395 9bae55d1 Panagiotis Kanavos
396 9bae55d1 Panagiotis Kanavos
397 9bae55d1 Panagiotis Kanavos
      //show context menu, if requested
398 9bae55d1 Panagiotis Kanavos
      if (me.IsMatch(MenuActivation))
399 9bae55d1 Panagiotis Kanavos
      {
400 9bae55d1 Panagiotis Kanavos
        if (me == MouseEvent.IconLeftMouseUp)
401 9bae55d1 Panagiotis Kanavos
        {
402 9bae55d1 Panagiotis Kanavos
          //show context menu once we are sure it's not a double click
403 9bae55d1 Panagiotis Kanavos
          delayedTimerAction = () =>
404 9bae55d1 Panagiotis Kanavos
                                 {
405 9bae55d1 Panagiotis Kanavos
                                   LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this);
406 9bae55d1 Panagiotis Kanavos
                                   ShowContextMenu(cursorPosition);
407 9bae55d1 Panagiotis Kanavos
                                 };
408 9bae55d1 Panagiotis Kanavos
          singleClickTimer.Change(WinApi.GetDoubleClickTime(), Timeout.Infinite);
409 9bae55d1 Panagiotis Kanavos
          isLeftClickCommandInvoked = true;
410 9bae55d1 Panagiotis Kanavos
        }
411 9bae55d1 Panagiotis Kanavos
        else
412 9bae55d1 Panagiotis Kanavos
        {
413 9bae55d1 Panagiotis Kanavos
          //show context menu immediately
414 9bae55d1 Panagiotis Kanavos
          ShowContextMenu(cursorPosition);
415 9bae55d1 Panagiotis Kanavos
        }
416 9bae55d1 Panagiotis Kanavos
      }
417 9bae55d1 Panagiotis Kanavos
418 9bae55d1 Panagiotis Kanavos
      //make sure the left click command is invoked on mouse clicks
419 9bae55d1 Panagiotis Kanavos
      if (me == MouseEvent.IconLeftMouseUp && !isLeftClickCommandInvoked)
420 9bae55d1 Panagiotis Kanavos
      {
421 9bae55d1 Panagiotis Kanavos
        //show context menu once we are sure it's not a double click
422 9bae55d1 Panagiotis Kanavos
        delayedTimerAction = () => LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this);
423 9bae55d1 Panagiotis Kanavos
        singleClickTimer.Change(WinApi.GetDoubleClickTime(), Timeout.Infinite);
424 9bae55d1 Panagiotis Kanavos
      }
425 9bae55d1 Panagiotis Kanavos
426 9bae55d1 Panagiotis Kanavos
    }
427 9bae55d1 Panagiotis Kanavos
428 9bae55d1 Panagiotis Kanavos
    #endregion
429 9bae55d1 Panagiotis Kanavos
430 9bae55d1 Panagiotis Kanavos
    #region ToolTips
431 9bae55d1 Panagiotis Kanavos
432 9bae55d1 Panagiotis Kanavos
    /// <summary>
433 9bae55d1 Panagiotis Kanavos
    /// Displays a custom tooltip, if available. This method is only
434 9bae55d1 Panagiotis Kanavos
    /// invoked for Windows Vista and above.
435 9bae55d1 Panagiotis Kanavos
    /// </summary>
436 9bae55d1 Panagiotis Kanavos
    /// <param name="visible">Whether to show or hide the tooltip.</param>
437 9bae55d1 Panagiotis Kanavos
    private void OnToolTipChange(bool visible)
438 9bae55d1 Panagiotis Kanavos
    {
439 9bae55d1 Panagiotis Kanavos
      //if we don't have a tooltip, there's nothing to do here...
440 9bae55d1 Panagiotis Kanavos
      if (TrayToolTipResolved == null) return;
441 9bae55d1 Panagiotis Kanavos
442 9bae55d1 Panagiotis Kanavos
      if (visible)
443 9bae55d1 Panagiotis Kanavos
      {
444 9bae55d1 Panagiotis Kanavos
        if (IsPopupOpen)
445 9bae55d1 Panagiotis Kanavos
        {
446 9bae55d1 Panagiotis Kanavos
          //ignore if we are already displaying something down there
447 9bae55d1 Panagiotis Kanavos
          return;
448 9bae55d1 Panagiotis Kanavos
        }
449 9bae55d1 Panagiotis Kanavos
450 9bae55d1 Panagiotis Kanavos
        var args = RaisePreviewTrayToolTipOpenEvent();
451 9bae55d1 Panagiotis Kanavos
        if (args.Handled) return;
452 9bae55d1 Panagiotis Kanavos
453 9bae55d1 Panagiotis Kanavos
        TrayToolTipResolved.IsOpen = true;
454 9bae55d1 Panagiotis Kanavos
455 9bae55d1 Panagiotis Kanavos
        //raise attached event first
456 9bae55d1 Panagiotis Kanavos
        if (TrayToolTip != null) RaiseToolTipOpenedEvent(TrayToolTip);
457 9bae55d1 Panagiotis Kanavos
        
458 9bae55d1 Panagiotis Kanavos
        //bubble routed event
459 9bae55d1 Panagiotis Kanavos
        RaiseTrayToolTipOpenEvent();
460 9bae55d1 Panagiotis Kanavos
      }
461 9bae55d1 Panagiotis Kanavos
      else
462 9bae55d1 Panagiotis Kanavos
      {
463 9bae55d1 Panagiotis Kanavos
        var args = RaisePreviewTrayToolTipCloseEvent();
464 9bae55d1 Panagiotis Kanavos
        if (args.Handled) return;
465 9bae55d1 Panagiotis Kanavos
466 9bae55d1 Panagiotis Kanavos
        //raise attached event first
467 9bae55d1 Panagiotis Kanavos
        if (TrayToolTip != null) RaiseToolTipCloseEvent(TrayToolTip);
468 9bae55d1 Panagiotis Kanavos
469 9bae55d1 Panagiotis Kanavos
        TrayToolTipResolved.IsOpen = false;
470 9bae55d1 Panagiotis Kanavos
471 9bae55d1 Panagiotis Kanavos
        //bubble event
472 9bae55d1 Panagiotis Kanavos
        RaiseTrayToolTipCloseEvent();
473 9bae55d1 Panagiotis Kanavos
      }
474 9bae55d1 Panagiotis Kanavos
    }
475 9bae55d1 Panagiotis Kanavos
476 9bae55d1 Panagiotis Kanavos
477 9bae55d1 Panagiotis Kanavos
    /// <summary>
478 9bae55d1 Panagiotis Kanavos
    /// Creates a <see cref="ToolTip"/> control that either
479 9bae55d1 Panagiotis Kanavos
    /// wraps the currently set <see cref="TrayToolTip"/>
480 9bae55d1 Panagiotis Kanavos
    /// control or the <see cref="ToolTipText"/> string.<br/>
481 9bae55d1 Panagiotis Kanavos
    /// If <see cref="TrayToolTip"/> itself is already
482 9bae55d1 Panagiotis Kanavos
    /// a <see cref="ToolTip"/> instance, it will be used directly.
483 9bae55d1 Panagiotis Kanavos
    /// </summary>
484 9bae55d1 Panagiotis Kanavos
    /// <remarks>We use a <see cref="ToolTip"/> rather than
485 9bae55d1 Panagiotis Kanavos
    /// <see cref="Popup"/> because there was no way to prevent a
486 9bae55d1 Panagiotis Kanavos
    /// popup from causing cyclic open/close commands if it was
487 9bae55d1 Panagiotis Kanavos
    /// placed under the mouse. ToolTip internally uses a Popup of
488 9bae55d1 Panagiotis Kanavos
    /// its own, but takes advance of Popup's internal <see cref="Popup.HitTestable"/>
489 9bae55d1 Panagiotis Kanavos
    /// property which prevents this issue.</remarks>
490 9bae55d1 Panagiotis Kanavos
    private void CreateCustomToolTip()
491 9bae55d1 Panagiotis Kanavos
    {
492 9bae55d1 Panagiotis Kanavos
      //check if the item itself is a tooltip
493 9bae55d1 Panagiotis Kanavos
      ToolTip tt = TrayToolTip as ToolTip;
494 9bae55d1 Panagiotis Kanavos
495 9bae55d1 Panagiotis Kanavos
      if (tt == null && TrayToolTip != null)
496 9bae55d1 Panagiotis Kanavos
      {
497 9bae55d1 Panagiotis Kanavos
        //create an invisible tooltip that hosts the UIElement
498 9bae55d1 Panagiotis Kanavos
        tt = new ToolTip();
499 9bae55d1 Panagiotis Kanavos
        tt.Placement = PlacementMode.Mouse;
500 9bae55d1 Panagiotis Kanavos
501 9bae55d1 Panagiotis Kanavos
        //do *not* set the placement target, as it causes the popup to become hidden if the
502 9bae55d1 Panagiotis Kanavos
        //TaskbarIcon's parent is hidden, too. At runtime, the parent can be resolved through
503 9bae55d1 Panagiotis Kanavos
        //the ParentTaskbarIcon attached dependency property:
504 9bae55d1 Panagiotis Kanavos
        //tt.PlacementTarget = this;
505 9bae55d1 Panagiotis Kanavos
506 9bae55d1 Panagiotis Kanavos
        //make sure the tooltip is invisible
507 9bae55d1 Panagiotis Kanavos
        tt.HasDropShadow = false;
508 9bae55d1 Panagiotis Kanavos
        tt.BorderThickness = new Thickness(0);
509 9bae55d1 Panagiotis Kanavos
        tt.Background = System.Windows.Media.Brushes.Transparent;
510 9bae55d1 Panagiotis Kanavos
511 9bae55d1 Panagiotis Kanavos
        //setting the 
512 9bae55d1 Panagiotis Kanavos
        tt.StaysOpen = true;
513 9bae55d1 Panagiotis Kanavos
        tt.Content = TrayToolTip;
514 9bae55d1 Panagiotis Kanavos
      }
515 9bae55d1 Panagiotis Kanavos
      else if (tt == null && !String.IsNullOrEmpty(ToolTipText))
516 9bae55d1 Panagiotis Kanavos
      {
517 9bae55d1 Panagiotis Kanavos
        //create a simple tooltip for the string
518 9bae55d1 Panagiotis Kanavos
        tt = new ToolTip();
519 9bae55d1 Panagiotis Kanavos
        tt.Content = ToolTipText;
520 9bae55d1 Panagiotis Kanavos
      }
521 9bae55d1 Panagiotis Kanavos
522 9bae55d1 Panagiotis Kanavos
      //the tooltip explicitly gets the DataContext of this instance.
523 9bae55d1 Panagiotis Kanavos
      //If there is no DataContext, the TaskbarIcon assigns itself
524 9bae55d1 Panagiotis Kanavos
      if (tt != null)
525 9bae55d1 Panagiotis Kanavos
      {
526 9bae55d1 Panagiotis Kanavos
        UpdateDataContext(tt, null, DataContext);
527 9bae55d1 Panagiotis Kanavos
      }
528 9bae55d1 Panagiotis Kanavos
529 9bae55d1 Panagiotis Kanavos
      //store a reference to the used tooltip
530 9bae55d1 Panagiotis Kanavos
      SetTrayToolTipResolved(tt);
531 9bae55d1 Panagiotis Kanavos
    }
532 9bae55d1 Panagiotis Kanavos
533 9bae55d1 Panagiotis Kanavos
534 9bae55d1 Panagiotis Kanavos
    /// <summary>
535 9bae55d1 Panagiotis Kanavos
    /// Sets tooltip settings for the class depending on defined
536 9bae55d1 Panagiotis Kanavos
    /// dependency properties and OS support.
537 9bae55d1 Panagiotis Kanavos
    /// </summary>
538 9bae55d1 Panagiotis Kanavos
    private void WriteToolTipSettings()
539 9bae55d1 Panagiotis Kanavos
    {
540 9bae55d1 Panagiotis Kanavos
      const IconDataMembers flags = IconDataMembers.Tip;
541 9bae55d1 Panagiotis Kanavos
      iconData.ToolTipText = ToolTipText;
542 9bae55d1 Panagiotis Kanavos
543 9bae55d1 Panagiotis Kanavos
      if (messageSink.Version == NotifyIconVersion.Vista)
544 9bae55d1 Panagiotis Kanavos
      {
545 9bae55d1 Panagiotis Kanavos
        //we need to set a tooltip text to get tooltip events from the
546 9bae55d1 Panagiotis Kanavos
        //taskbar icon
547 9bae55d1 Panagiotis Kanavos
        if (String.IsNullOrEmpty(iconData.ToolTipText) && TrayToolTipResolved != null)
548 9bae55d1 Panagiotis Kanavos
        {
549 9bae55d1 Panagiotis Kanavos
          //if we have not tooltip text but a custom tooltip, we
550 9bae55d1 Panagiotis Kanavos
          //need to set a dummy value (we're displaying the ToolTip control, not the string)
551 9bae55d1 Panagiotis Kanavos
          iconData.ToolTipText = "ToolTip";
552 9bae55d1 Panagiotis Kanavos
        }
553 9bae55d1 Panagiotis Kanavos
      }
554 9bae55d1 Panagiotis Kanavos
555 9bae55d1 Panagiotis Kanavos
      //update the tooltip text
556 9bae55d1 Panagiotis Kanavos
      Util.WriteIconData(ref iconData, NotifyCommand.Modify, flags);
557 9bae55d1 Panagiotis Kanavos
    }
558 9bae55d1 Panagiotis Kanavos
559 9bae55d1 Panagiotis Kanavos
    #endregion
560 9bae55d1 Panagiotis Kanavos
561 9bae55d1 Panagiotis Kanavos
    #region Custom Popup
562 9bae55d1 Panagiotis Kanavos
563 9bae55d1 Panagiotis Kanavos
    /// <summary>
564 9bae55d1 Panagiotis Kanavos
    /// Creates a <see cref="ToolTip"/> control that either
565 9bae55d1 Panagiotis Kanavos
    /// wraps the currently set <see cref="TrayToolTip"/>
566 9bae55d1 Panagiotis Kanavos
    /// control or the <see cref="ToolTipText"/> string.<br/>
567 9bae55d1 Panagiotis Kanavos
    /// If <see cref="TrayToolTip"/> itself is already
568 9bae55d1 Panagiotis Kanavos
    /// a <see cref="ToolTip"/> instance, it will be used directly.
569 9bae55d1 Panagiotis Kanavos
    /// </summary>
570 9bae55d1 Panagiotis Kanavos
    /// <remarks>We use a <see cref="ToolTip"/> rather than
571 9bae55d1 Panagiotis Kanavos
    /// <see cref="Popup"/> because there was no way to prevent a
572 9bae55d1 Panagiotis Kanavos
    /// popup from causing cyclic open/close commands if it was
573 9bae55d1 Panagiotis Kanavos
    /// placed under the mouse. ToolTip internally uses a Popup of
574 9bae55d1 Panagiotis Kanavos
    /// its own, but takes advance of Popup's internal <see cref="Popup.HitTestable"/>
575 9bae55d1 Panagiotis Kanavos
    /// property which prevents this issue.</remarks>
576 9bae55d1 Panagiotis Kanavos
    private void CreatePopup()
577 9bae55d1 Panagiotis Kanavos
    {
578 9bae55d1 Panagiotis Kanavos
      //check if the item itself is a popup
579 9bae55d1 Panagiotis Kanavos
      Popup popup = TrayPopup as Popup;
580 9bae55d1 Panagiotis Kanavos
581 9bae55d1 Panagiotis Kanavos
      if (popup == null && TrayPopup != null)
582 9bae55d1 Panagiotis Kanavos
      {
583 9bae55d1 Panagiotis Kanavos
        //create an invisible popup that hosts the UIElement
584 9bae55d1 Panagiotis Kanavos
        popup = new Popup();
585 9bae55d1 Panagiotis Kanavos
        popup.AllowsTransparency = true;
586 9bae55d1 Panagiotis Kanavos
587 9bae55d1 Panagiotis Kanavos
        //don't animate by default - devs can use attached
588 9bae55d1 Panagiotis Kanavos
        //events or override
589 9bae55d1 Panagiotis Kanavos
        popup.PopupAnimation = PopupAnimation.None;
590 9bae55d1 Panagiotis Kanavos
591 9bae55d1 Panagiotis Kanavos
        //the CreateRootPopup method outputs binding errors in the debug window because
592 9bae55d1 Panagiotis Kanavos
        //it tries to bind to "Popup-specific" properties in case they are provided by the child.
593 9bae55d1 Panagiotis Kanavos
        //We don't need that so just assign the control as the child.
594 9bae55d1 Panagiotis Kanavos
        popup.Child = TrayPopup;
595 9bae55d1 Panagiotis Kanavos
596 9bae55d1 Panagiotis Kanavos
        //do *not* set the placement target, as it causes the popup to become hidden if the
597 9bae55d1 Panagiotis Kanavos
        //TaskbarIcon's parent is hidden, too. At runtime, the parent can be resolved through
598 9bae55d1 Panagiotis Kanavos
        //the ParentTaskbarIcon attached dependency property:
599 9bae55d1 Panagiotis Kanavos
        //popup.PlacementTarget = this;
600 9bae55d1 Panagiotis Kanavos
601 9bae55d1 Panagiotis Kanavos
        popup.Placement = PlacementMode.AbsolutePoint;
602 9bae55d1 Panagiotis Kanavos
        popup.StaysOpen = false;
603 9bae55d1 Panagiotis Kanavos
      }
604 9bae55d1 Panagiotis Kanavos
605 9bae55d1 Panagiotis Kanavos
      //the popup explicitly gets the DataContext of this instance.
606 9bae55d1 Panagiotis Kanavos
      //If there is no DataContext, the TaskbarIcon assigns itself
607 9bae55d1 Panagiotis Kanavos
      if (popup != null)
608 9bae55d1 Panagiotis Kanavos
      {
609 9bae55d1 Panagiotis Kanavos
        UpdateDataContext(popup, null, DataContext);
610 9bae55d1 Panagiotis Kanavos
      }
611 9bae55d1 Panagiotis Kanavos
612 9bae55d1 Panagiotis Kanavos
      //store a reference to the used tooltip
613 9bae55d1 Panagiotis Kanavos
      SetTrayPopupResolved(popup);
614 9bae55d1 Panagiotis Kanavos
    }
615 9bae55d1 Panagiotis Kanavos
616 9bae55d1 Panagiotis Kanavos
617 9bae55d1 Panagiotis Kanavos
    /// <summary>
618 9bae55d1 Panagiotis Kanavos
    /// Displays the <see cref="TrayPopup"/> control if
619 9bae55d1 Panagiotis Kanavos
    /// it was set.
620 9bae55d1 Panagiotis Kanavos
    /// </summary>
621 9bae55d1 Panagiotis Kanavos
    private void ShowTrayPopup(Point cursorPosition)
622 9bae55d1 Panagiotis Kanavos
    {
623 9bae55d1 Panagiotis Kanavos
      if (IsDisposed) return;
624 9bae55d1 Panagiotis Kanavos
625 9bae55d1 Panagiotis Kanavos
      //raise preview event no matter whether popup is currently set
626 9bae55d1 Panagiotis Kanavos
      //or not (enables client to set it on demand)
627 9bae55d1 Panagiotis Kanavos
      var args = RaisePreviewTrayPopupOpenEvent();
628 9bae55d1 Panagiotis Kanavos
      if (args.Handled) return;
629 9bae55d1 Panagiotis Kanavos
630 9bae55d1 Panagiotis Kanavos
      if (TrayPopup != null)
631 9bae55d1 Panagiotis Kanavos
      {
632 9bae55d1 Panagiotis Kanavos
        //use absolute position, but place the popup centered above the icon
633 9bae55d1 Panagiotis Kanavos
        TrayPopupResolved.Placement = PlacementMode.AbsolutePoint;
634 9bae55d1 Panagiotis Kanavos
        TrayPopupResolved.HorizontalOffset = cursorPosition.X;
635 9bae55d1 Panagiotis Kanavos
        TrayPopupResolved.VerticalOffset = cursorPosition.Y;
636 9bae55d1 Panagiotis Kanavos
637 9bae55d1 Panagiotis Kanavos
        //open popup
638 9bae55d1 Panagiotis Kanavos
        TrayPopupResolved.IsOpen = true;
639 9bae55d1 Panagiotis Kanavos
640 9bae55d1 Panagiotis Kanavos
641 9bae55d1 Panagiotis Kanavos
        IntPtr handle = IntPtr.Zero;
642 9bae55d1 Panagiotis Kanavos
        if (TrayPopupResolved.Child != null)
643 9bae55d1 Panagiotis Kanavos
        {
644 9bae55d1 Panagiotis Kanavos
          //try to get a handle on the popup itself (via its child)
645 9bae55d1 Panagiotis Kanavos
          HwndSource source = (HwndSource)PresentationSource.FromVisual(TrayPopupResolved.Child);
646 9bae55d1 Panagiotis Kanavos
          if (source != null) handle = source.Handle;
647 9bae55d1 Panagiotis Kanavos
        }
648 9bae55d1 Panagiotis Kanavos
649 9bae55d1 Panagiotis Kanavos
        //if we don't have a handle for the popup, fall back to the message sink
650 9bae55d1 Panagiotis Kanavos
        if (handle == IntPtr.Zero) handle = messageSink.MessageWindowHandle;
651 9bae55d1 Panagiotis Kanavos
652 9bae55d1 Panagiotis Kanavos
        //activate either popup or message sink to track deactivation.
653 9bae55d1 Panagiotis Kanavos
        //otherwise, the popup does not close if the user clicks somewhere else
654 9bae55d1 Panagiotis Kanavos
        WinApi.SetForegroundWindow(handle);
655 9bae55d1 Panagiotis Kanavos
656 9bae55d1 Panagiotis Kanavos
        //raise attached event - item should never be null unless developers
657 9bae55d1 Panagiotis Kanavos
        //changed the CustomPopup directly...
658 9bae55d1 Panagiotis Kanavos
        if (TrayPopup != null) RaisePopupOpenedEvent(TrayPopup);
659 9bae55d1 Panagiotis Kanavos
660 9bae55d1 Panagiotis Kanavos
        //bubble routed event
661 9bae55d1 Panagiotis Kanavos
        RaiseTrayPopupOpenEvent();
662 9bae55d1 Panagiotis Kanavos
      }
663 9bae55d1 Panagiotis Kanavos
    }
664 9bae55d1 Panagiotis Kanavos
665 9bae55d1 Panagiotis Kanavos
    #endregion
666 9bae55d1 Panagiotis Kanavos
667 9bae55d1 Panagiotis Kanavos
    #region Context Menu
668 9bae55d1 Panagiotis Kanavos
669 9bae55d1 Panagiotis Kanavos
    /// <summary>
670 9bae55d1 Panagiotis Kanavos
    /// Displays the <see cref="ContextMenu"/> if
671 9bae55d1 Panagiotis Kanavos
    /// it was set.
672 9bae55d1 Panagiotis Kanavos
    /// </summary>
673 9bae55d1 Panagiotis Kanavos
    private void ShowContextMenu(Point cursorPosition)
674 9bae55d1 Panagiotis Kanavos
    {
675 9bae55d1 Panagiotis Kanavos
      if (IsDisposed) return;
676 9bae55d1 Panagiotis Kanavos
677 9bae55d1 Panagiotis Kanavos
      //raise preview event no matter whether context menu is currently set
678 9bae55d1 Panagiotis Kanavos
      //or not (enables client to set it on demand)
679 9bae55d1 Panagiotis Kanavos
      var args = RaisePreviewTrayContextMenuOpenEvent();
680 9bae55d1 Panagiotis Kanavos
      if (args.Handled) return;
681 9bae55d1 Panagiotis Kanavos
682 9bae55d1 Panagiotis Kanavos
      if (ContextMenu != null)
683 9bae55d1 Panagiotis Kanavos
      {
684 9bae55d1 Panagiotis Kanavos
        //use absolute position
685 9bae55d1 Panagiotis Kanavos
        ContextMenu.Placement = PlacementMode.AbsolutePoint;
686 9bae55d1 Panagiotis Kanavos
        ContextMenu.HorizontalOffset = cursorPosition.X;
687 9bae55d1 Panagiotis Kanavos
        ContextMenu.VerticalOffset = cursorPosition.Y;
688 9bae55d1 Panagiotis Kanavos
        ContextMenu.IsOpen = true;
689 9bae55d1 Panagiotis Kanavos
690 9bae55d1 Panagiotis Kanavos
        //activate the message window to track deactivation - otherwise, the context menu
691 9bae55d1 Panagiotis Kanavos
        //does not close if the user clicks somewhere else
692 9bae55d1 Panagiotis Kanavos
        WinApi.SetForegroundWindow(messageSink.MessageWindowHandle);
693 9bae55d1 Panagiotis Kanavos
694 9bae55d1 Panagiotis Kanavos
        //bubble event
695 9bae55d1 Panagiotis Kanavos
        RaiseTrayContextMenuOpenEvent();
696 9bae55d1 Panagiotis Kanavos
      }
697 9bae55d1 Panagiotis Kanavos
    }
698 9bae55d1 Panagiotis Kanavos
699 9bae55d1 Panagiotis Kanavos
    #endregion
700 9bae55d1 Panagiotis Kanavos
701 9bae55d1 Panagiotis Kanavos
    #region Balloon Tips
702 9bae55d1 Panagiotis Kanavos
703 9bae55d1 Panagiotis Kanavos
    /// <summary>
704 9bae55d1 Panagiotis Kanavos
    /// Bubbles events if a balloon ToolTip was displayed
705 9bae55d1 Panagiotis Kanavos
    /// or removed.
706 9bae55d1 Panagiotis Kanavos
    /// </summary>
707 9bae55d1 Panagiotis Kanavos
    /// <param name="visible">Whether the ToolTip was just displayed
708 9bae55d1 Panagiotis Kanavos
    /// or removed.</param>
709 9bae55d1 Panagiotis Kanavos
    private void OnBalloonToolTipChanged(bool visible)
710 9bae55d1 Panagiotis Kanavos
    {
711 9bae55d1 Panagiotis Kanavos
      if (visible)
712 9bae55d1 Panagiotis Kanavos
      {
713 9bae55d1 Panagiotis Kanavos
        RaiseTrayBalloonTipShownEvent();
714 9bae55d1 Panagiotis Kanavos
      }
715 9bae55d1 Panagiotis Kanavos
      else
716 9bae55d1 Panagiotis Kanavos
      {
717 9bae55d1 Panagiotis Kanavos
        RaiseTrayBalloonTipClosedEvent();
718 9bae55d1 Panagiotis Kanavos
      }
719 9bae55d1 Panagiotis Kanavos
    }
720 9bae55d1 Panagiotis Kanavos
721 9bae55d1 Panagiotis Kanavos
    /// <summary>
722 9bae55d1 Panagiotis Kanavos
    /// Displays a balloon tip with the specified title,
723 9bae55d1 Panagiotis Kanavos
    /// text, and icon in the taskbar for the specified time period.
724 9bae55d1 Panagiotis Kanavos
    /// </summary>
725 9bae55d1 Panagiotis Kanavos
    /// <param name="title">The title to display on the balloon tip.</param>
726 9bae55d1 Panagiotis Kanavos
    /// <param name="message">The text to display on the balloon tip.</param>
727 9bae55d1 Panagiotis Kanavos
    /// <param name="symbol">A symbol that indicates the severity.</param>
728 9bae55d1 Panagiotis Kanavos
    public void ShowBalloonTip(string title, string message, BalloonIcon symbol)
729 9bae55d1 Panagiotis Kanavos
    {
730 9bae55d1 Panagiotis Kanavos
      lock (this)
731 9bae55d1 Panagiotis Kanavos
      {
732 9bae55d1 Panagiotis Kanavos
        ShowBalloonTip(title, message, symbol.GetBalloonFlag(), IntPtr.Zero);
733 9bae55d1 Panagiotis Kanavos
      }
734 9bae55d1 Panagiotis Kanavos
    }
735 9bae55d1 Panagiotis Kanavos
736 9bae55d1 Panagiotis Kanavos
737 9bae55d1 Panagiotis Kanavos
    /// <summary>
738 9bae55d1 Panagiotis Kanavos
    /// Displays a balloon tip with the specified title,
739 9bae55d1 Panagiotis Kanavos
    /// text, and a custom icon in the taskbar for the specified time period.
740 9bae55d1 Panagiotis Kanavos
    /// </summary>
741 9bae55d1 Panagiotis Kanavos
    /// <param name="title">The title to display on the balloon tip.</param>
742 9bae55d1 Panagiotis Kanavos
    /// <param name="message">The text to display on the balloon tip.</param>
743 9bae55d1 Panagiotis Kanavos
    /// <param name="customIcon">A custom icon.</param>
744 9bae55d1 Panagiotis Kanavos
    /// <exception cref="ArgumentNullException">If <paramref name="customIcon"/>
745 9bae55d1 Panagiotis Kanavos
    /// is a null reference.</exception>
746 9bae55d1 Panagiotis Kanavos
    public void ShowBalloonTip(string title, string message, Icon customIcon)
747 9bae55d1 Panagiotis Kanavos
    {
748 9bae55d1 Panagiotis Kanavos
      if (customIcon == null) throw new ArgumentNullException("customIcon");
749 9bae55d1 Panagiotis Kanavos
750 9bae55d1 Panagiotis Kanavos
      lock (this)
751 9bae55d1 Panagiotis Kanavos
      {
752 9bae55d1 Panagiotis Kanavos
        ShowBalloonTip(title, message, BalloonFlags.User, customIcon.Handle);
753 9bae55d1 Panagiotis Kanavos
      }
754 9bae55d1 Panagiotis Kanavos
    }
755 9bae55d1 Panagiotis Kanavos
756 9bae55d1 Panagiotis Kanavos
757 9bae55d1 Panagiotis Kanavos
    /// <summary>
758 9bae55d1 Panagiotis Kanavos
    /// Invokes <see cref="WinApi.Shell_NotifyIcon"/> in order to display
759 9bae55d1 Panagiotis Kanavos
    /// a given balloon ToolTip.
760 9bae55d1 Panagiotis Kanavos
    /// </summary>
761 9bae55d1 Panagiotis Kanavos
    /// <param name="title">The title to display on the balloon tip.</param>
762 9bae55d1 Panagiotis Kanavos
    /// <param name="message">The text to display on the balloon tip.</param>
763 9bae55d1 Panagiotis Kanavos
    /// <param name="flags">Indicates what icon to use.</param>
764 9bae55d1 Panagiotis Kanavos
    /// <param name="balloonIconHandle">A handle to a custom icon, if any, or
765 9bae55d1 Panagiotis Kanavos
    /// <see cref="IntPtr.Zero"/>.</param>
766 9bae55d1 Panagiotis Kanavos
    private void ShowBalloonTip(string title, string message, BalloonFlags flags, IntPtr balloonIconHandle)
767 9bae55d1 Panagiotis Kanavos
    {
768 9bae55d1 Panagiotis Kanavos
      EnsureNotDisposed();
769 9bae55d1 Panagiotis Kanavos
770 9bae55d1 Panagiotis Kanavos
      iconData.BalloonText = message ?? String.Empty;
771 9bae55d1 Panagiotis Kanavos
      iconData.BalloonTitle = title ?? String.Empty;
772 9bae55d1 Panagiotis Kanavos
773 9bae55d1 Panagiotis Kanavos
      iconData.BalloonFlags = flags;
774 9bae55d1 Panagiotis Kanavos
      iconData.CustomBalloonIconHandle = balloonIconHandle;
775 9bae55d1 Panagiotis Kanavos
      Util.WriteIconData(ref iconData, NotifyCommand.Modify, IconDataMembers.Info | IconDataMembers.Icon);
776 9bae55d1 Panagiotis Kanavos
    }
777 9bae55d1 Panagiotis Kanavos
778 9bae55d1 Panagiotis Kanavos
779 9bae55d1 Panagiotis Kanavos
    /// <summary>
780 9bae55d1 Panagiotis Kanavos
    /// Hides a balloon ToolTip, if any is displayed.
781 9bae55d1 Panagiotis Kanavos
    /// </summary>
782 9bae55d1 Panagiotis Kanavos
    public void HideBalloonTip()
783 9bae55d1 Panagiotis Kanavos
    {
784 9bae55d1 Panagiotis Kanavos
      EnsureNotDisposed();
785 9bae55d1 Panagiotis Kanavos
786 9bae55d1 Panagiotis Kanavos
      //reset balloon by just setting the info to an empty string
787 9bae55d1 Panagiotis Kanavos
      iconData.BalloonText = iconData.BalloonTitle = String.Empty;
788 9bae55d1 Panagiotis Kanavos
      Util.WriteIconData(ref iconData, NotifyCommand.Modify, IconDataMembers.Info);
789 9bae55d1 Panagiotis Kanavos
    }
790 9bae55d1 Panagiotis Kanavos
791 9bae55d1 Panagiotis Kanavos
    #endregion
792 9bae55d1 Panagiotis Kanavos
793 9bae55d1 Panagiotis Kanavos
    #region Single Click Timer event
794 9bae55d1 Panagiotis Kanavos
795 9bae55d1 Panagiotis Kanavos
    /// <summary>
796 9bae55d1 Panagiotis Kanavos
    /// Performs a delayed action if the user requested an action
797 9bae55d1 Panagiotis Kanavos
    /// based on a single click of the left mouse.<br/>
798 9bae55d1 Panagiotis Kanavos
    /// This method is invoked by the <see cref="singleClickTimer"/>.
799 9bae55d1 Panagiotis Kanavos
    /// </summary>
800 9bae55d1 Panagiotis Kanavos
    private void DoSingleClickAction(object state)
801 9bae55d1 Panagiotis Kanavos
    {
802 9bae55d1 Panagiotis Kanavos
      if (IsDisposed) return;
803 9bae55d1 Panagiotis Kanavos
804 9bae55d1 Panagiotis Kanavos
      //run action
805 9bae55d1 Panagiotis Kanavos
      Action action = delayedTimerAction;
806 9bae55d1 Panagiotis Kanavos
      if (action != null)
807 9bae55d1 Panagiotis Kanavos
      {
808 9bae55d1 Panagiotis Kanavos
        //cleanup action
809 9bae55d1 Panagiotis Kanavos
        delayedTimerAction = null;
810 9bae55d1 Panagiotis Kanavos
811 9bae55d1 Panagiotis Kanavos
        //switch to UI thread
812 9bae55d1 Panagiotis Kanavos
        this.GetDispatcher().Invoke(action);
813 9bae55d1 Panagiotis Kanavos
      }
814 9bae55d1 Panagiotis Kanavos
    }
815 9bae55d1 Panagiotis Kanavos
816 9bae55d1 Panagiotis Kanavos
    #endregion
817 9bae55d1 Panagiotis Kanavos
818 9bae55d1 Panagiotis Kanavos
    #region Set Version (API)
819 9bae55d1 Panagiotis Kanavos
820 9bae55d1 Panagiotis Kanavos
    /// <summary>
821 9bae55d1 Panagiotis Kanavos
    /// Sets the version flag for the <see cref="iconData"/>.
822 9bae55d1 Panagiotis Kanavos
    /// </summary>
823 9bae55d1 Panagiotis Kanavos
    private void SetVersion()
824 9bae55d1 Panagiotis Kanavos
    {
825 9bae55d1 Panagiotis Kanavos
      iconData.VersionOrTimeout = (uint) NotifyIconVersion.Vista;
826 9bae55d1 Panagiotis Kanavos
      bool status = WinApi.Shell_NotifyIcon(NotifyCommand.SetVersion, ref iconData);
827 9bae55d1 Panagiotis Kanavos
828 9bae55d1 Panagiotis Kanavos
      if (!status)
829 9bae55d1 Panagiotis Kanavos
      {
830 9bae55d1 Panagiotis Kanavos
        iconData.VersionOrTimeout = (uint) NotifyIconVersion.Win2000;
831 9bae55d1 Panagiotis Kanavos
        status = Util.WriteIconData(ref iconData, NotifyCommand.SetVersion);
832 9bae55d1 Panagiotis Kanavos
      }
833 9bae55d1 Panagiotis Kanavos
834 9bae55d1 Panagiotis Kanavos
      if (!status)
835 9bae55d1 Panagiotis Kanavos
      {
836 9bae55d1 Panagiotis Kanavos
        iconData.VersionOrTimeout = (uint) NotifyIconVersion.Win95;
837 9bae55d1 Panagiotis Kanavos
        status = Util.WriteIconData(ref iconData, NotifyCommand.SetVersion);
838 9bae55d1 Panagiotis Kanavos
      }
839 9bae55d1 Panagiotis Kanavos
840 9bae55d1 Panagiotis Kanavos
      if (!status)
841 9bae55d1 Panagiotis Kanavos
      {
842 9bae55d1 Panagiotis Kanavos
        Debug.Fail("Could not set version");
843 9bae55d1 Panagiotis Kanavos
      }
844 9bae55d1 Panagiotis Kanavos
    }
845 9bae55d1 Panagiotis Kanavos
846 9bae55d1 Panagiotis Kanavos
    #endregion
847 9bae55d1 Panagiotis Kanavos
848 9bae55d1 Panagiotis Kanavos
    #region Create / Remove Taskbar Icon
849 9bae55d1 Panagiotis Kanavos
850 9bae55d1 Panagiotis Kanavos
    /// <summary>
851 9bae55d1 Panagiotis Kanavos
    /// Recreates the taskbar icon if the whole taskbar was
852 9bae55d1 Panagiotis Kanavos
    /// recreated (e.g. because Explorer was shut down).
853 9bae55d1 Panagiotis Kanavos
    /// </summary>
854 9bae55d1 Panagiotis Kanavos
    private void OnTaskbarCreated()
855 9bae55d1 Panagiotis Kanavos
    {
856 9bae55d1 Panagiotis Kanavos
      IsTaskbarIconCreated = false;
857 9bae55d1 Panagiotis Kanavos
      CreateTaskbarIcon();
858 9bae55d1 Panagiotis Kanavos
    }
859 9bae55d1 Panagiotis Kanavos
860 9bae55d1 Panagiotis Kanavos
861 9bae55d1 Panagiotis Kanavos
    /// <summary>
862 9bae55d1 Panagiotis Kanavos
    /// Creates the taskbar icon. This message is invoked during initialization,
863 9bae55d1 Panagiotis Kanavos
    /// if the taskbar is restarted, and whenever the icon is displayed.
864 9bae55d1 Panagiotis Kanavos
    /// </summary>
865 9bae55d1 Panagiotis Kanavos
    private void CreateTaskbarIcon()
866 9bae55d1 Panagiotis Kanavos
    {
867 9bae55d1 Panagiotis Kanavos
      lock (this)
868 9bae55d1 Panagiotis Kanavos
      {
869 9bae55d1 Panagiotis Kanavos
        if (!IsTaskbarIconCreated)
870 9bae55d1 Panagiotis Kanavos
        {
871 9bae55d1 Panagiotis Kanavos
          const IconDataMembers members = IconDataMembers.Message
872 9bae55d1 Panagiotis Kanavos
                                          | IconDataMembers.Icon
873 9bae55d1 Panagiotis Kanavos
                                          | IconDataMembers.Tip;
874 9bae55d1 Panagiotis Kanavos
875 9bae55d1 Panagiotis Kanavos
          //write initial configuration
876 9bae55d1 Panagiotis Kanavos
          var status = Util.WriteIconData(ref iconData, NotifyCommand.Add, members);
877 9bae55d1 Panagiotis Kanavos
          if (!status)
878 9bae55d1 Panagiotis Kanavos
          {
879 9bae55d1 Panagiotis Kanavos
            throw new Win32Exception("Could not create icon data");
880 9bae55d1 Panagiotis Kanavos
          }
881 9bae55d1 Panagiotis Kanavos
882 9bae55d1 Panagiotis Kanavos
          //set to most recent version
883 9bae55d1 Panagiotis Kanavos
          SetVersion();
884 9bae55d1 Panagiotis Kanavos
          messageSink.Version = (NotifyIconVersion) iconData.VersionOrTimeout;
885 9bae55d1 Panagiotis Kanavos
886 9bae55d1 Panagiotis Kanavos
          IsTaskbarIconCreated = true;
887 9bae55d1 Panagiotis Kanavos
        }
888 9bae55d1 Panagiotis Kanavos
      }
889 9bae55d1 Panagiotis Kanavos
    }
890 9bae55d1 Panagiotis Kanavos
891 9bae55d1 Panagiotis Kanavos
892 9bae55d1 Panagiotis Kanavos
    /// <summary>
893 9bae55d1 Panagiotis Kanavos
    /// Closes the taskbar icon if required.
894 9bae55d1 Panagiotis Kanavos
    /// </summary>
895 9bae55d1 Panagiotis Kanavos
    private void RemoveTaskbarIcon()
896 9bae55d1 Panagiotis Kanavos
    {
897 9bae55d1 Panagiotis Kanavos
      lock (this)
898 9bae55d1 Panagiotis Kanavos
      {
899 9bae55d1 Panagiotis Kanavos
        if (IsTaskbarIconCreated)
900 9bae55d1 Panagiotis Kanavos
        {
901 9bae55d1 Panagiotis Kanavos
          Util.WriteIconData(ref iconData, NotifyCommand.Delete, IconDataMembers.Message);
902 9bae55d1 Panagiotis Kanavos
          IsTaskbarIconCreated = false;
903 9bae55d1 Panagiotis Kanavos
        }
904 9bae55d1 Panagiotis Kanavos
      }
905 9bae55d1 Panagiotis Kanavos
    }
906 9bae55d1 Panagiotis Kanavos
907 9bae55d1 Panagiotis Kanavos
    #endregion
908 9bae55d1 Panagiotis Kanavos
909 9bae55d1 Panagiotis Kanavos
    #region Dispose / Exit
910 9bae55d1 Panagiotis Kanavos
911 9bae55d1 Panagiotis Kanavos
    /// <summary>
912 9bae55d1 Panagiotis Kanavos
    /// Set to true as soon as <see cref="Dispose"/>
913 9bae55d1 Panagiotis Kanavos
    /// has been invoked.
914 9bae55d1 Panagiotis Kanavos
    /// </summary>
915 9bae55d1 Panagiotis Kanavos
    public bool IsDisposed { get; private set; }
916 9bae55d1 Panagiotis Kanavos
917 9bae55d1 Panagiotis Kanavos
918 9bae55d1 Panagiotis Kanavos
    /// <summary>
919 9bae55d1 Panagiotis Kanavos
    /// Checks if the object has been disposed and
920 9bae55d1 Panagiotis Kanavos
    /// raises a <see cref="ObjectDisposedException"/> in case
921 9bae55d1 Panagiotis Kanavos
    /// the <see cref="IsDisposed"/> flag is true.
922 9bae55d1 Panagiotis Kanavos
    /// </summary>
923 9bae55d1 Panagiotis Kanavos
    private void EnsureNotDisposed()
924 9bae55d1 Panagiotis Kanavos
    {
925 9bae55d1 Panagiotis Kanavos
      if (IsDisposed) throw new ObjectDisposedException(Name ?? GetType().FullName);
926 9bae55d1 Panagiotis Kanavos
    }
927 9bae55d1 Panagiotis Kanavos
928 9bae55d1 Panagiotis Kanavos
929 9bae55d1 Panagiotis Kanavos
    /// <summary>
930 9bae55d1 Panagiotis Kanavos
    /// Disposes the class if the application exits.
931 9bae55d1 Panagiotis Kanavos
    /// </summary>
932 9bae55d1 Panagiotis Kanavos
    private void OnExit(object sender, EventArgs e)
933 9bae55d1 Panagiotis Kanavos
    {
934 9bae55d1 Panagiotis Kanavos
      Dispose();
935 9bae55d1 Panagiotis Kanavos
    }
936 9bae55d1 Panagiotis Kanavos
937 9bae55d1 Panagiotis Kanavos
938 9bae55d1 Panagiotis Kanavos
    /// <summary>
939 9bae55d1 Panagiotis Kanavos
    /// This destructor will run only if the <see cref="Dispose()"/>
940 9bae55d1 Panagiotis Kanavos
    /// method does not get called. This gives this base class the
941 9bae55d1 Panagiotis Kanavos
    /// opportunity to finalize.
942 9bae55d1 Panagiotis Kanavos
    /// <para>
943 9bae55d1 Panagiotis Kanavos
    /// Important: Do not provide destructors in types derived from
944 9bae55d1 Panagiotis Kanavos
    /// this class.
945 9bae55d1 Panagiotis Kanavos
    /// </para>
946 9bae55d1 Panagiotis Kanavos
    /// </summary>
947 9bae55d1 Panagiotis Kanavos
    ~TaskbarIcon()
948 9bae55d1 Panagiotis Kanavos
    {
949 9bae55d1 Panagiotis Kanavos
      Dispose(false);
950 9bae55d1 Panagiotis Kanavos
    }
951 9bae55d1 Panagiotis Kanavos
952 9bae55d1 Panagiotis Kanavos
953 9bae55d1 Panagiotis Kanavos
    /// <summary>
954 9bae55d1 Panagiotis Kanavos
    /// Disposes the object.
955 9bae55d1 Panagiotis Kanavos
    /// </summary>
956 9bae55d1 Panagiotis Kanavos
    /// <remarks>This method is not virtual by design. Derived classes
957 9bae55d1 Panagiotis Kanavos
    /// should override <see cref="Dispose(bool)"/>.
958 9bae55d1 Panagiotis Kanavos
    /// </remarks>
959 9bae55d1 Panagiotis Kanavos
    public void Dispose()
960 9bae55d1 Panagiotis Kanavos
    {
961 9bae55d1 Panagiotis Kanavos
      Dispose(true);
962 9bae55d1 Panagiotis Kanavos
963 9bae55d1 Panagiotis Kanavos
      // This object will be cleaned up by the Dispose method.
964 9bae55d1 Panagiotis Kanavos
      // Therefore, you should call GC.SupressFinalize to
965 9bae55d1 Panagiotis Kanavos
      // take this object off the finalization queue 
966 9bae55d1 Panagiotis Kanavos
      // and prevent finalization code for this object
967 9bae55d1 Panagiotis Kanavos
      // from executing a second time.
968 9bae55d1 Panagiotis Kanavos
      GC.SuppressFinalize(this);
969 9bae55d1 Panagiotis Kanavos
    }
970 9bae55d1 Panagiotis Kanavos
971 9bae55d1 Panagiotis Kanavos
972 9bae55d1 Panagiotis Kanavos
    /// <summary>
973 9bae55d1 Panagiotis Kanavos
    /// Closes the tray and releases all resources.
974 9bae55d1 Panagiotis Kanavos
    /// </summary>
975 9bae55d1 Panagiotis Kanavos
    /// <summary>
976 9bae55d1 Panagiotis Kanavos
    /// <c>Dispose(bool disposing)</c> executes in two distinct scenarios.
977 9bae55d1 Panagiotis Kanavos
    /// If disposing equals <c>true</c>, the method has been called directly
978 9bae55d1 Panagiotis Kanavos
    /// or indirectly by a user's code. Managed and unmanaged resources
979 9bae55d1 Panagiotis Kanavos
    /// can be disposed.
980 9bae55d1 Panagiotis Kanavos
    /// </summary>
981 9bae55d1 Panagiotis Kanavos
    /// <param name="disposing">If disposing equals <c>false</c>, the method
982 9bae55d1 Panagiotis Kanavos
    /// has been called by the runtime from inside the finalizer and you
983 9bae55d1 Panagiotis Kanavos
    /// should not reference other objects. Only unmanaged resources can
984 9bae55d1 Panagiotis Kanavos
    /// be disposed.</param>
985 9bae55d1 Panagiotis Kanavos
    /// <remarks>Check the <see cref="IsDisposed"/> property to determine whether
986 9bae55d1 Panagiotis Kanavos
    /// the method has already been called.</remarks>
987 9bae55d1 Panagiotis Kanavos
    private void Dispose(bool disposing)
988 9bae55d1 Panagiotis Kanavos
    {
989 9bae55d1 Panagiotis Kanavos
      //don't do anything if the component is already disposed
990 9bae55d1 Panagiotis Kanavos
      if (IsDisposed || !disposing) return;
991 9bae55d1 Panagiotis Kanavos
992 9bae55d1 Panagiotis Kanavos
      lock (this)
993 9bae55d1 Panagiotis Kanavos
      {
994 9bae55d1 Panagiotis Kanavos
        IsDisposed = true;
995 9bae55d1 Panagiotis Kanavos
996 9bae55d1 Panagiotis Kanavos
        //deregister application event listener
997 9bae55d1 Panagiotis Kanavos
        if (Application.Current != null)
998 9bae55d1 Panagiotis Kanavos
        {
999 9bae55d1 Panagiotis Kanavos
          Application.Current.Exit -= OnExit;
1000 9bae55d1 Panagiotis Kanavos
        }
1001 9bae55d1 Panagiotis Kanavos
1002 9bae55d1 Panagiotis Kanavos
        //stop timers
1003 9bae55d1 Panagiotis Kanavos
        singleClickTimer.Dispose();
1004 9bae55d1 Panagiotis Kanavos
        balloonCloseTimer.Dispose();
1005 9bae55d1 Panagiotis Kanavos
1006 9bae55d1 Panagiotis Kanavos
        //dispose message sink
1007 9bae55d1 Panagiotis Kanavos
        messageSink.Dispose();
1008 9bae55d1 Panagiotis Kanavos
1009 9bae55d1 Panagiotis Kanavos
        //remove icon
1010 9bae55d1 Panagiotis Kanavos
        RemoveTaskbarIcon();
1011 9bae55d1 Panagiotis Kanavos
      }
1012 9bae55d1 Panagiotis Kanavos
    }
1013 9bae55d1 Panagiotis Kanavos
1014 9bae55d1 Panagiotis Kanavos
    #endregion
1015 9bae55d1 Panagiotis Kanavos
  }
1016 9bae55d1 Panagiotis Kanavos
}