2006-12-31 Chris Toshok <toshok@ximian.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / NotifyIcon.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Peter Bartok    pbartok@novell.com
24 //
25 //
26
27 // NOT COMPLETE
28
29 using System;
30 using System.ComponentModel;
31 using System.ComponentModel.Design;
32 using System.Drawing;
33
34 namespace System.Windows.Forms {
35         [DefaultProperty("Text")]
36 #if NET_2_0
37         [DefaultEvent("MouseDoubleClick")]
38 #else
39         [DefaultEvent("MouseDown")]
40 #endif
41         [Designer ("System.Windows.Forms.Design.NotifyIconDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
42         [ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Allow)]
43         public sealed class NotifyIcon : Component {
44                 #region Local Variables
45                 private ContextMenu             context_menu;
46                 private Icon                    icon;
47                 private Bitmap                  icon_bitmap;
48                 private string                  text;
49                 private bool                    visible;
50                 private NotifyIconWindow        window;
51                 private bool                    systray_active;
52                 private ToolTip                 tooltip;
53                 #endregion      // Local Variables
54
55                 #region NotifyIconWindow Class
56                 internal class NotifyIconWindow : Form {
57                         NotifyIcon      owner;
58                         Rectangle       rect;
59
60                         public NotifyIconWindow(NotifyIcon owner) {
61                                 this.owner = owner;
62                                 is_visible = false;
63                                 rect = new Rectangle(0, 0, 1, 1);
64
65                                 FormBorderStyle = FormBorderStyle.None;
66
67                                 //CreateControl();
68
69                                 SizeChanged += new EventHandler(HandleSizeChanged);
70
71                                 // Events that need to be sent to our parent
72                                 Click += new EventHandler(HandleClick);
73                                 DoubleClick += new EventHandler(HandleDoubleClick);
74                                 MouseDown +=new MouseEventHandler(HandleMouseDown);
75                                 MouseUp +=new MouseEventHandler(HandleMouseUp);
76                                 MouseMove +=new MouseEventHandler(HandleMouseMove);
77                                 ContextMenu = owner.context_menu;
78                         }
79
80                         protected override CreateParams CreateParams {
81                                 get {
82                                         CreateParams cp;
83
84                                         cp = base.CreateParams;
85
86                                         cp.Parent = IntPtr.Zero;
87                                         cp.Style = (int)WindowStyles.WS_POPUP;
88                                         cp.Style |= (int)WindowStyles.WS_CLIPSIBLINGS;
89
90                                         cp.ExStyle = (int)(WindowExStyles.WS_EX_TOOLWINDOW);
91
92                                         return cp;
93                                 }
94                         }
95
96                         protected override void WndProc(ref Message m) {
97                                 switch((Msg)m.Msg) {
98                                                 //
99                                                 //  NotifyIcon does CONTEXTMENU on mouse up, not down
100                                                 //  so we swallow the message here, and handle it on our own
101                                                 // 
102                                         case Msg.WM_CONTEXTMENU:
103                                                 return;
104
105                                         case Msg.WM_USER: {
106                                                 switch ((Msg)m.LParam.ToInt32()) {
107                                                         case Msg.WM_LBUTTONDOWN: {
108                                                                 owner.OnMouseDown (new MouseEventArgs(MouseButtons.Left, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
109                                                                 return;
110                                                         }
111
112                                                         case Msg.WM_LBUTTONUP: {
113                                                                 owner.OnMouseUp (new MouseEventArgs(MouseButtons.Left, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
114                                                                 owner.OnClick (EventArgs.Empty);
115                                                                 return;
116                                                         }
117
118                                                         case Msg.WM_LBUTTONDBLCLK: {
119                                                                 owner.OnDoubleClick (EventArgs.Empty);
120                                                                 return;
121                                                         }
122
123                                                         case Msg.WM_MOUSEMOVE: {
124                                                                 owner.OnMouseMove (new MouseEventArgs(MouseButtons.None, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
125                                                                 return;
126                                                         }
127
128                                                         case Msg.WM_RBUTTONDOWN: {
129                                                                 owner.OnMouseDown (new MouseEventArgs(MouseButtons.Right, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
130                                                                 return;
131                                                         }
132
133                                                         case Msg.WM_RBUTTONUP: {
134                                                                 owner.OnMouseUp (new MouseEventArgs(MouseButtons.Right, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
135                                                                 owner.OnClick (EventArgs.Empty);
136                                                                 return;
137                                                         }
138
139                                                         case Msg.WM_RBUTTONDBLCLK: {
140                                                                 owner.OnDoubleClick (EventArgs.Empty);
141                                                                 return;
142                                                         }
143                                                 }
144                                                 return;
145                                         }
146                                 }
147                                 base.WndProc (ref m);
148                         }
149
150                         internal void CalculateIconRect() {
151                                 int             x;
152                                 int             y;
153                                 int             size;
154
155                                 // Icons are always square. Try to center them in the window
156                                 if (ClientRectangle.Width < ClientRectangle.Height) {
157                                         size = ClientRectangle.Width;
158                                 } else {
159                                         size = ClientRectangle.Height;
160                                 }
161                                 x = this.ClientRectangle.Width / 2 - size / 2;
162                                 y = this.ClientRectangle.Height / 2 - size / 2;
163                                 rect = new Rectangle(x, y, size, size);
164
165                                 Bounds = new Rectangle (0, 0, size, size);
166                         }
167
168                         internal override void OnPaintInternal (PaintEventArgs e) {
169                                 if (owner.icon != null) {
170                                         e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(SystemColors.Window), rect);
171                                         e.Graphics.DrawImage(owner.icon_bitmap,
172                                                              rect,
173                                                              new Rectangle (0, 0, owner.icon_bitmap.Width, owner.icon_bitmap.Height),
174                                                              GraphicsUnit.Pixel);
175
176                                 }
177                         }
178
179                         internal void InternalRecreateHandle () {
180                                 base.RecreateHandle ();
181                         }
182
183
184                         private void HandleSizeChanged(object sender, EventArgs e) {
185                                 owner.Recalculate ();
186                         }
187
188                         private void HandleClick (object sender, EventArgs e)
189                         {
190                                 owner.OnClick (e);
191                         }
192
193                         private void HandleDoubleClick (object sender, EventArgs e)
194                         {
195                                 owner.OnDoubleClick (e);
196                         }
197
198                         private void HandleMouseDown (object sender, MouseEventArgs e)
199                         {
200                                 owner.OnMouseDown (e);
201                         }
202
203                         private void HandleMouseUp (object sender, MouseEventArgs e)
204                         {
205                                 owner.OnMouseUp (e);
206                         }
207
208                         private void HandleMouseMove (object sender, MouseEventArgs e)
209                         {
210                                 owner.OnMouseMove (e);
211                         }
212                 }
213                 #endregion      // NotifyIconWindow Class
214
215                 #region Public Constructors
216                 public NotifyIcon() {
217                         window = new NotifyIconWindow(this);
218                         systray_active = false;
219                 }
220
221                 public NotifyIcon(System.ComponentModel.IContainer container) : this() {
222                 }
223                 #endregion      // Public Constructors
224
225                 #region Private Methods
226                 private void OnClick (EventArgs e)
227                 {
228                         EventHandler eh = (EventHandler)(Events [ClickEvent]);
229                         if (eh != null)
230                                 eh (this, e);
231                 }
232
233                 private void OnDoubleClick (EventArgs e)
234                 {
235                         EventHandler eh = (EventHandler)(Events [DoubleClickEvent]);
236                         if (eh != null)
237                                 eh (this, e);
238                 }
239
240                 private void OnMouseDown (MouseEventArgs e)
241                 {
242                         MouseEventHandler eh = (MouseEventHandler)(Events [MouseDownEvent]);
243                         if (eh != null)
244                                 eh (this, e);
245                 }
246
247                 private void OnMouseUp (MouseEventArgs e)
248                 {
249                         if ((e.Button & MouseButtons.Right) == MouseButtons.Right && context_menu != null)
250                                 context_menu.Show (window, new Point(e.X, e.Y));
251
252                         MouseEventHandler eh = (MouseEventHandler)(Events [MouseUpEvent]);
253                         if (eh != null)
254                                 eh (this, e);
255                 }
256
257                 private void OnMouseMove (MouseEventArgs e)
258                 {
259                         MouseEventHandler eh = (MouseEventHandler)(Events [MouseMoveEvent]);
260                         if (eh != null)
261                                 eh (this, e);
262                 }
263
264                 private void Recalculate () 
265                 {
266                         window.CalculateIconRect ();
267
268                         if (systray_active)
269                                 UpdateSystray ();
270                 }
271
272                 private void ShowSystray()
273                 {
274                         systray_active = true;
275
276                         if (icon == null)
277                                 return;
278
279                         icon_bitmap = icon.ToBitmap();
280
281                         XplatUI.SystrayAdd(window.Handle, text, icon, out tooltip);
282                 }
283
284                 private void HideSystray()
285                 {
286                         if (!systray_active) {
287                                 return;
288                         }
289
290                         systray_active = false;
291                         XplatUI.SystrayRemove(window.Handle, ref tooltip);
292                 }
293
294                 private void UpdateSystray()
295                 {
296                         if (icon_bitmap != null) {
297                                 icon_bitmap.Dispose();
298                         }
299
300                         if (icon != null) {
301                                 icon_bitmap = icon.ToBitmap();
302                         }
303
304                         XplatUI.SystrayChange(window.Handle, text, icon, ref tooltip);
305                         window.Invalidate();
306                 }
307                 #endregion      // Private Methods
308
309                 #region Public Instance Properties
310                 [DefaultValue(null)]
311 #if NET_2_0
312                 [Browsable (false)]
313 #endif
314                 public ContextMenu ContextMenu {
315                         get {
316                                 return context_menu;
317                         }
318
319                         set {
320                                 if (context_menu != value) {
321                                         context_menu = value;
322                                         window.ContextMenu = value;
323                                 }
324                         }
325                 }
326
327                 [Localizable(true)]
328                 [DefaultValue(null)]
329                 public Icon Icon {
330                         get {
331                                 return icon;
332                         }
333
334                         set {
335                                 if (icon != value) {
336                                         icon = value;
337                                         if (text == string.Empty && icon == null) {
338                                                 HideSystray ();
339                                         }
340                                         else {
341                                                 Recalculate ();
342                                         }
343                                 }
344                         }
345                 }
346
347 #if NET_2_0
348                 [Localizable(true)]
349                 [DefaultValue ("")]
350                 [Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design,
351                          typeof (System.Drawing.Design.UITypeEditor))]
352 #endif
353                 public string Text {
354                         get {
355                                 return text;
356                         }
357
358                         set {
359                                 if (text != value) {
360                                         if (value.Length >= 64) {
361                                                 throw new ArgumentException("ToolTip length must be less than 64 characters long", "Text");
362                                         }
363                                         text = value;
364                                         if (text == string.Empty && icon == null) {
365                                                 HideSystray();
366                                         } else {
367                                                 Recalculate ();
368                                         }
369                                 }
370                         }
371                 }
372
373                 [Localizable(true)]
374                 [DefaultValue(false)]
375                 public bool Visible {
376                         get {
377                                 return visible;
378                         }
379
380                         set {
381                                 if (visible != value) {
382                                         visible = value;
383
384                                         // Let our control know, too
385                                         window.is_visible = value;
386
387                                         if (visible) {
388                                                 ShowSystray ();
389                                         } else {
390                                                 HideSystray();
391                                         }
392                                 }
393                         }
394                 }
395                 #endregion      // Public Instance Properties
396
397                 #region Protected Instance Methods
398                 protected override void Dispose(bool disposing) {
399                         if (icon_bitmap != null) {
400                                 icon_bitmap.Dispose();
401                         }
402
403                         if (disposing)
404                                 icon = null;
405
406                         base.Dispose (disposing);
407                 }
408
409                 #endregion      // Protected Instance Methods
410
411                 #region Events
412                 static object ClickEvent = new object ();
413                 static object DoubleClickEvent = new object ();
414                 static object MouseDownEvent = new object ();
415                 static object MouseMoveEvent = new object ();
416                 static object MouseUpEvent = new object ();
417
418 #if NET_2_0
419                 [MWFCategory("Action")]
420 #else
421                 [Category("Action")]
422 #endif
423                 public event EventHandler Click {
424                         add { Events.AddHandler (ClickEvent, value); }
425                         remove { Events.RemoveHandler (ClickEvent, value); }
426                 }
427
428 #if NET_2_0
429                 [MWFCategory("Action")]
430 #else
431                 [Category("Action")]
432 #endif
433                 public event EventHandler DoubleClick {
434                         add { Events.AddHandler (DoubleClickEvent, value); }
435                         remove { Events.RemoveHandler (DoubleClickEvent, value); }
436                 }
437
438                 public event MouseEventHandler MouseDown {
439                         add { Events.AddHandler (MouseDownEvent, value); }
440                         remove { Events.RemoveHandler (MouseDownEvent, value); }
441                 }
442
443                 public event MouseEventHandler MouseMove {
444                         add { Events.AddHandler (MouseMoveEvent, value); }
445                         remove { Events.RemoveHandler (MouseMoveEvent, value); }
446                 }
447
448                 public event MouseEventHandler MouseUp {
449                         add { Events.AddHandler (MouseUpEvent, value); }
450                         remove { Events.RemoveHandler (MouseUpEvent, value); }
451                 }
452
453                 #endregion      // Events
454         }
455 }