2006-12-26 Jonathan Pobst <monkey@jpobst.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         [DefaultEvent("MouseDown")]
37         [Designer ("System.Windows.Forms.Design.NotifyIconDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
38         [ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Allow)]
39         public sealed class NotifyIcon : Component {
40                 #region Local Variables
41                 private ContextMenu             context_menu;
42                 private Icon                    icon;
43                 private Bitmap                  icon_bitmap;
44                 private string                  text;
45                 private bool                    visible;
46                 private NotifyIconWindow        window;
47                 private bool                    systray_active;
48                 private ToolTip                 tooltip;
49                 #endregion      // Local Variables
50
51                 #region NotifyIconWindow Class
52                 internal class NotifyIconWindow : Form {
53                         NotifyIcon      owner;
54                         Rectangle       rect;
55
56                         public NotifyIconWindow(NotifyIcon owner) {
57                                 this.owner = owner;
58                                 is_visible = false;
59                                 rect = new Rectangle(0, 0, 1, 1);
60
61                                 FormBorderStyle = FormBorderStyle.None;
62
63                                 //CreateControl();
64
65                                 SizeChanged += new EventHandler(HandleSizeChanged);
66
67                                 // Events that need to be sent to our parent
68                                 Click += new EventHandler(HandleClick);
69                                 DoubleClick += new EventHandler(HandleDoubleClick);
70                                 MouseDown +=new MouseEventHandler(HandleMouseDown);
71                                 MouseUp +=new MouseEventHandler(HandleMouseUp);
72                                 MouseMove +=new MouseEventHandler(HandleMouseMove);
73                                 ContextMenu = owner.context_menu;
74                         }
75
76                         protected override CreateParams CreateParams {
77                                 get {
78                                         CreateParams cp;
79
80                                         cp = base.CreateParams;
81
82                                         cp.Parent = IntPtr.Zero;
83                                         cp.Style = (int)WindowStyles.WS_POPUP;
84                                         cp.Style |= (int)WindowStyles.WS_CLIPSIBLINGS;
85
86                                         cp.ExStyle = (int)(WindowExStyles.WS_EX_TOOLWINDOW);
87
88                                         return cp;
89                                 }
90                         }
91
92                         protected override void WndProc(ref Message m) {
93                                 switch((Msg)m.Msg) {
94                                                 //
95                                                 //  NotifyIcon does CONTEXTMENU on mouse up, not down
96                                                 //  so we swallow the message here, and handle it on our own
97                                                 // 
98                                         case Msg.WM_CONTEXTMENU:
99                                                 return;
100
101                                         case Msg.WM_USER: {
102                                                 switch ((Msg)m.LParam.ToInt32()) {
103                                                         case Msg.WM_LBUTTONDOWN: {
104                                                                 owner.OnMouseDown (new MouseEventArgs(MouseButtons.Left, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
105                                                                 return;
106                                                         }
107
108                                                         case Msg.WM_LBUTTONUP: {
109                                                                 owner.OnMouseUp (new MouseEventArgs(MouseButtons.Left, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
110                                                                 owner.OnClick (EventArgs.Empty);
111                                                                 return;
112                                                         }
113
114                                                         case Msg.WM_LBUTTONDBLCLK: {
115                                                                 owner.OnDoubleClick (EventArgs.Empty);
116                                                                 return;
117                                                         }
118
119                                                         case Msg.WM_MOUSEMOVE: {
120                                                                 owner.OnMouseMove (new MouseEventArgs(MouseButtons.None, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
121                                                                 return;
122                                                         }
123
124                                                         case Msg.WM_RBUTTONDOWN: {
125                                                                 owner.OnMouseDown (new MouseEventArgs(MouseButtons.Right, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
126                                                                 return;
127                                                         }
128
129                                                         case Msg.WM_RBUTTONUP: {
130                                                                 owner.OnMouseUp (new MouseEventArgs(MouseButtons.Right, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
131                                                                 owner.OnClick (EventArgs.Empty);
132                                                                 return;
133                                                         }
134
135                                                         case Msg.WM_RBUTTONDBLCLK: {
136                                                                 owner.OnDoubleClick (EventArgs.Empty);
137                                                                 return;
138                                                         }
139                                                 }
140                                                 return;
141                                         }
142                                 }
143                                 base.WndProc (ref m);
144                         }
145
146                         internal void CalculateIconRect() {
147                                 int             x;
148                                 int             y;
149                                 int             size;
150
151                                 // Icons are always square. Try to center them in the window
152                                 if (ClientRectangle.Width < ClientRectangle.Height) {
153                                         size = ClientRectangle.Width;
154                                 } else {
155                                         size = ClientRectangle.Height;
156                                 }
157                                 x = this.ClientRectangle.Width / 2 - size / 2;
158                                 y = this.ClientRectangle.Height / 2 - size / 2;
159                                 rect = new Rectangle(x, y, size, size);
160
161                                 Bounds = new Rectangle (0, 0, size, size);
162                         }
163
164                         internal override void OnPaintInternal (PaintEventArgs e) {
165                                 if (owner.icon != null) {
166                                         e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(SystemColors.Window), rect);
167                                         e.Graphics.DrawImage(owner.icon_bitmap,
168                                                              rect,
169                                                              new Rectangle (0, 0, owner.icon_bitmap.Width, owner.icon_bitmap.Height),
170                                                              GraphicsUnit.Pixel);
171
172                                 }
173                         }
174
175                         internal void InternalRecreateHandle () {
176                                 base.RecreateHandle ();
177                         }
178
179
180                         private void HandleSizeChanged(object sender, EventArgs e) {
181                                 owner.Recalculate ();
182                         }
183
184                         private void HandleClick (object sender, EventArgs e)
185                         {
186                                 owner.OnClick (e);
187                         }
188
189                         private void HandleDoubleClick (object sender, EventArgs e)
190                         {
191                                 owner.OnDoubleClick (e);
192                         }
193
194                         private void HandleMouseDown (object sender, MouseEventArgs e)
195                         {
196                                 owner.OnMouseDown (e);
197                         }
198
199                         private void HandleMouseUp (object sender, MouseEventArgs e)
200                         {
201                                 owner.OnMouseUp (e);
202                         }
203
204                         private void HandleMouseMove (object sender, MouseEventArgs e)
205                         {
206                                 owner.OnMouseMove (e);
207                         }
208                 }
209                 #endregion      // NotifyIconWindow Class
210
211                 #region Public Constructors
212                 public NotifyIcon() {
213                         window = new NotifyIconWindow(this);
214                         systray_active = false;
215                 }
216
217                 public NotifyIcon(System.ComponentModel.IContainer container) : this() {
218                 }
219                 #endregion      // Public Constructors
220
221                 #region Private Methods
222                 private void OnClick (EventArgs e)
223                 {
224                         EventHandler eh = (EventHandler)(Events [ClickEvent]);
225                         if (eh != null)
226                                 eh (this, e);
227                 }
228
229                 private void OnDoubleClick (EventArgs e)
230                 {
231                         EventHandler eh = (EventHandler)(Events [DoubleClickEvent]);
232                         if (eh != null)
233                                 eh (this, e);
234                 }
235
236                 private void OnMouseDown (MouseEventArgs e)
237                 {
238                         MouseEventHandler eh = (MouseEventHandler)(Events [MouseDownEvent]);
239                         if (eh != null)
240                                 eh (this, e);
241                 }
242
243                 private void OnMouseUp (MouseEventArgs e)
244                 {
245                         if ((e.Button & MouseButtons.Right) == MouseButtons.Right && context_menu != null)
246                                 context_menu.Show (window, new Point(e.X, e.Y));
247
248                         MouseEventHandler eh = (MouseEventHandler)(Events [MouseUpEvent]);
249                         if (eh != null)
250                                 eh (this, e);
251                 }
252
253                 private void OnMouseMove (MouseEventArgs e)
254                 {
255                         MouseEventHandler eh = (MouseEventHandler)(Events [MouseMoveEvent]);
256                         if (eh != null)
257                                 eh (this, e);
258                 }
259
260                 private void Recalculate () 
261                 {
262                         window.CalculateIconRect ();
263
264                         if (systray_active)
265                                 UpdateSystray ();
266                 }
267
268                 private void ShowSystray()
269                 {
270                         systray_active = true;
271
272                         if (icon == null)
273                                 return;
274
275                         icon_bitmap = icon.ToBitmap();
276
277                         XplatUI.SystrayAdd(window.Handle, text, icon, out tooltip);
278                 }
279
280                 private void HideSystray()
281                 {
282                         if (!systray_active) {
283                                 return;
284                         }
285
286                         systray_active = false;
287                         XplatUI.SystrayRemove(window.Handle, ref tooltip);
288                 }
289
290                 private void UpdateSystray()
291                 {
292                         if (icon_bitmap != null) {
293                                 icon_bitmap.Dispose();
294                         }
295
296                         if (icon != null) {
297                                 icon_bitmap = icon.ToBitmap();
298                         }
299
300                         XplatUI.SystrayChange(window.Handle, text, icon, ref tooltip);
301                         window.Invalidate();
302                 }
303                 #endregion      // Private Methods
304
305                 #region Public Instance Properties
306                 [DefaultValue(null)]
307                 public ContextMenu ContextMenu {
308                         get {
309                                 return context_menu;
310                         }
311
312                         set {
313                                 if (context_menu != value) {
314                                         context_menu = value;
315                                         window.ContextMenu = value;
316                                 }
317                         }
318                 }
319
320                 [Localizable(true)]
321                 [DefaultValue(null)]
322                 public Icon Icon {
323                         get {
324                                 return icon;
325                         }
326
327                         set {
328                                 if (icon != value) {
329                                         icon = value;
330                                         if (text == string.Empty && icon == null) {
331                                                 HideSystray ();
332                                         }
333                                         else {
334                                                 Recalculate ();
335                                         }
336                                 }
337                         }
338                 }
339
340                 [Localizable(true)]
341                 public string Text {
342                         get {
343                                 return text;
344                         }
345
346                         set {
347                                 if (text != value) {
348                                         if (value.Length >= 64) {
349                                                 throw new ArgumentException("ToolTip length must be less than 64 characters long", "Text");
350                                         }
351                                         text = value;
352                                         if (text == string.Empty && icon == null) {
353                                                 HideSystray();
354                                         } else {
355                                                 Recalculate ();
356                                         }
357                                 }
358                         }
359                 }
360
361                 [Localizable(true)]
362                 [DefaultValue(false)]
363                 public bool Visible {
364                         get {
365                                 return visible;
366                         }
367
368                         set {
369                                 if (visible != value) {
370                                         visible = value;
371
372                                         // Let our control know, too
373                                         window.is_visible = value;
374
375                                         if (visible) {
376                                                 ShowSystray ();
377                                         } else {
378                                                 HideSystray();
379                                         }
380                                 }
381                         }
382                 }
383                 #endregion      // Public Instance Properties
384
385                 #region Protected Instance Methods
386                 protected override void Dispose(bool disposing) {
387                         if (icon_bitmap != null) {
388                                 icon_bitmap.Dispose();
389                         }
390
391                         if (disposing)
392                                 icon = null;
393
394                         base.Dispose (disposing);
395                 }
396
397                 #endregion      // Protected Instance Methods
398
399                 #region Events
400                 static object ClickEvent = new object ();
401                 static object DoubleClickEvent = new object ();
402                 static object MouseDownEvent = new object ();
403                 static object MouseMoveEvent = new object ();
404                 static object MouseUpEvent = new object ();
405
406                 [Category("Action")]
407                 public event EventHandler Click {
408                         add { Events.AddHandler (ClickEvent, value); }
409                         remove { Events.RemoveHandler (ClickEvent, value); }
410                 }
411
412                 [Category("Action")]
413                 public event EventHandler DoubleClick {
414                         add { Events.AddHandler (DoubleClickEvent, value); }
415                         remove { Events.RemoveHandler (DoubleClickEvent, value); }
416                 }
417
418                 public event MouseEventHandler MouseDown {
419                         add { Events.AddHandler (MouseDownEvent, value); }
420                         remove { Events.RemoveHandler (MouseDownEvent, value); }
421                 }
422
423                 public event MouseEventHandler MouseMove {
424                         add { Events.AddHandler (MouseMoveEvent, value); }
425                         remove { Events.RemoveHandler (MouseMoveEvent, value); }
426                 }
427
428                 public event MouseEventHandler MouseUp {
429                         add { Events.AddHandler (MouseUpEvent, value); }
430                         remove { Events.RemoveHandler (MouseUpEvent, value); }
431                 }
432
433                 #endregion      // Events
434         }
435 }