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 | } |