2005-09-08 Peter Dennis Bartok <pbartok@novell.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 : System.ComponentModel.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 : Control {
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                                 CreateControl();
62
63                                 Paint += new PaintEventHandler(HandlePaint);
64                                 SizeChanged += new EventHandler(HandleSizeChanged);
65
66                                 // Events that need to be sent to our parent
67                                 Click += new EventHandler(HandleClick);
68                                 DoubleClick += new EventHandler(HandleDoubleClick);
69                                 MouseDown +=new MouseEventHandler(HandleMouseDown);
70                                 MouseUp +=new MouseEventHandler(HandleMouseUp);
71                                 MouseMove +=new MouseEventHandler(HandleMouseMove);
72                                 ContextMenu = owner.context_menu;
73                         }\r
74 \r
75                         protected override CreateParams CreateParams {\r
76                                 get {\r
77                                         CreateParams cp;\r
78 \r
79                                         cp = base.CreateParams;\r
80 \r
81                                         cp.Parent = IntPtr.Zero;\r
82                                         cp.Style = (int)WindowStyles.WS_POPUP;\r
83                                         cp.Style |= (int)WindowStyles.WS_CLIPSIBLINGS;\r
84 \r
85                                         cp.ExStyle = (int)(WindowStyles.WS_EX_TOOLWINDOW);
86 \r
87                                         return cp;\r
88                                 }\r
89                         }\r
90 \r
91                         protected override void WndProc(ref Message m) {\r
92                                 switch((Msg)m.Msg) {\r
93                                         case Msg.WM_NCPAINT: {\r
94                                                 PaintEventArgs  paint_event;
95
96                                                 paint_event = XplatUI.PaintEventStart(Handle, false);
97                                                 OnPaint(paint_event);
98                                                 XplatUI.PaintEventEnd(Handle, false);\r
99                                                 break;\r
100                                         }\r
101 \r
102                                         case Msg.WM_USER: {\r
103                                                 switch ((Msg)m.LParam.ToInt32()) {\r
104                                                         case Msg.WM_LBUTTONDOWN: {\r
105                                                                 HandleMouseDown(this, new MouseEventArgs(MouseButtons.Left, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));\r
106                                                                 return;\r
107                                                         }\r
108 \r
109                                                         case Msg.WM_LBUTTONUP: {\r
110                                                                 HandleMouseUp(this, new MouseEventArgs(MouseButtons.Left, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));\r
111                                                                 HandleClick(this, EventArgs.Empty);\r
112                                                                 return;\r
113                                                         }\r
114 \r
115                                                         case Msg.WM_LBUTTONDBLCLK: {\r
116                                                                 HandleDoubleClick(this, EventArgs.Empty);\r
117                                                                 return;\r
118                                                         }\r
119 \r
120                                                         case Msg.WM_MOUSEMOVE: {\r
121                                                                 HandleMouseMove(this, new MouseEventArgs(MouseButtons.None, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));\r
122                                                                 return;\r
123                                                         }\r
124 \r
125                                                         case Msg.WM_RBUTTONDOWN: {\r
126                                                                 HandleMouseDown(this, new MouseEventArgs(MouseButtons.Right, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));\r
127                                                                 return;\r
128                                                         }\r
129 \r
130                                                         case Msg.WM_RBUTTONUP: {\r
131                                                                 HandleMouseUp(this, new MouseEventArgs(MouseButtons.Right, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));\r
132                                                                 HandleClick(this, EventArgs.Empty);\r
133                                                                 return;\r
134                                                         }\r
135 \r
136                                                         case Msg.WM_RBUTTONDBLCLK: {\r
137                                                                 HandleDoubleClick(this, EventArgs.Empty);\r
138                                                                 return;\r
139                                                         }\r
140                                                 }\r
141                                                 return;\r
142                                         }\r
143                                 }\r
144                                 base.WndProc (ref m);\r
145                         }\r
146 \r
147                         internal void CalculateIconRect() {\r
148                                 if (owner != null && owner.icon != null) {\r
149                                         int             x;
150                                         int             y;
151                                         int             size;\r
152 \r
153                                         // Icons are always square. Try to center them in the window\r
154                                         if (ClientRectangle.Width < ClientRectangle.Height) {\r
155                                                 size = ClientRectangle.Width;\r
156                                         } else {\r
157                                                 size = ClientRectangle.Height;\r
158                                         }\r
159                                         x = this.ClientRectangle.Width / 2 - size / 2;\r
160                                         y = this.ClientRectangle.Height / 2 - size / 2;\r
161                                         rect = new Rectangle(x, y, size, size);\r
162 \r
163                                         // Force our window to be square\r
164                                         if (Width != size) {\r
165                                                 this.Width = size;\r
166                                         }\r
167 \r
168                                         if (Height != size) {\r
169                                                 this.Height = size;\r
170                                         }\r
171                                 }\r
172                         }\r
173 \r
174                         private void HandlePaint(object sender, PaintEventArgs e) {\r
175                                 if (owner.icon != null) {\r
176                                         e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(SystemColors.Window), rect);\r
177                                         e.Graphics.DrawImage(owner.icon_bitmap, rect);\r
178 \r
179                                 }\r
180                         }\r
181 \r
182                         private void HandleSizeChanged(object sender, EventArgs e) {\r
183                                 CalculateIconRect();\r
184                         }\r
185 \r
186                         private void HandleClick(object sender, EventArgs e) {\r
187                                 if (owner.Click != null) {\r
188                                         owner.Click(owner, e);\r
189                                 }\r
190                         }\r
191 \r
192                         private void HandleDoubleClick(object sender, EventArgs e) {\r
193                                 if (owner.DoubleClick != null) {\r
194                                         owner.DoubleClick(owner, e);\r
195                                 }\r
196                         }\r
197 \r
198                         private void HandleMouseDown(object sender, MouseEventArgs e) {\r
199                                 if (owner.MouseDown != null) {\r
200                                         owner.MouseDown(owner, e);\r
201                                 }\r
202                         }\r
203
204                         private void HandleMouseUp(object sender, MouseEventArgs e) {\r
205                                 if (owner.context_menu != null) {\r
206                                         owner.context_menu.Show(this, new Point(e.X, e.Y));\r
207                                 }\r
208 \r
209                                 if (owner.MouseUp != null) {\r
210                                         owner.MouseUp(owner, e);\r
211                                 }\r
212                         }\r
213 \r
214                         private void HandleMouseMove(object sender, MouseEventArgs e) {\r
215                                 if (owner.MouseMove != null) {\r
216                                         owner.MouseMove(owner, e);\r
217                                 }\r
218                         }\r
219                 }
220                 #endregion      // NotifyIconWindow Class
221
222                 #region Public Constructors
223                 public NotifyIcon() {
224                         window = new NotifyIconWindow(this);
225                         systray_active = false;
226                 }
227
228                 public NotifyIcon(System.ComponentModel.IContainer container) : this() {
229                 }
230                 #endregion      // Public Constructors
231
232                 #region Private Methods
233                 private void ShowSystray(bool property_changed) {
234                         if (property_changed) {
235                                 window.CalculateIconRect();
236                         }
237
238                         if (systray_active) {
239                                 if (property_changed) {
240                                         UpdateSystray();
241                                 }
242                                 return;
243                         }
244
245                         if (icon == null) {
246                                 return;
247                         }
248
249                         icon_bitmap = icon.ToBitmap();
250
251                         systray_active = true;
252                         XplatUI.SystrayAdd(window.Handle, text, icon, out tooltip);
253                 }
254
255                 private void HideSystray() {
256                         if (!systray_active) {
257                                 return;
258                         }
259
260                         systray_active = false;
261                         XplatUI.SystrayRemove(window.Handle, ref tooltip);
262                 }
263
264                 private void UpdateSystray() {
265                         if (icon_bitmap != null) {
266                                 icon_bitmap.Dispose();
267                         }
268
269                         if (icon != null) {
270                                 icon_bitmap = icon.ToBitmap();
271                         }
272
273                         XplatUI.SystrayChange(window.Handle, text, icon, ref tooltip);
274                         window.Invalidate();
275                 }
276                 #endregion      // Private Methods
277
278                 #region Public Instance Properties
279                 [DefaultValue(null)]
280                 public ContextMenu ContextMenu {
281                         get {
282                                 return context_menu;
283                         }
284
285                         set {
286                                 if (context_menu != value) {
287                                         context_menu = value;
288                                         window.ContextMenu = value;
289                                 }
290                         }
291                 }
292
293                 [Localizable(true)]
294                 [DefaultValue(null)]
295                 public Icon Icon {
296                         get {
297                                 return icon;
298                         }
299
300                         set {
301                                 if (icon != value) {
302                                         if (icon != null) {
303                                                 icon.Dispose();
304                                         }
305                                         icon = value;
306                                         ShowSystray(true);
307                                 }
308                         }
309                 }
310
311                 [Localizable(true)]
312                 public string Text {
313                         get {
314                                 return text;
315                         }
316
317                         set {
318                                 if (text != value) {
319                                         if (value.Length >= 64) {
320                                                 throw new ArgumentException("ToolTip length must be less than 64 characters long", "Text");
321                                         }
322                                         text = value;
323                                         if (text == string.Empty && icon == null) {
324                                                 HideSystray();
325                                         } else {
326                                                 ShowSystray(true);
327                                         }
328                                 }
329                         }
330                 }
331
332                 [Localizable(true)]
333                 [DefaultValue(false)]
334                 public bool Visible {
335                         get {
336                                 return visible;
337                         }
338
339                         set {
340                                 if (visible != value) {
341                                         visible = value;
342
343                                         // Let our control know, too
344                                         window.is_visible = value;
345
346                                         if (visible) {
347                                                 ShowSystray(false);
348                                         } else {
349                                                 HideSystray();
350                                         }
351                                 }
352                         }
353                 }
354                 #endregion      // Public Instance Properties
355
356                 #region Protected Instance Methods
357                 protected override void Dispose(bool disposing) {\r
358                         if (icon != null) {\r
359                                 icon.Dispose();\r
360                         }\r
361 \r
362                         if (icon_bitmap != null) {\r
363                                 icon_bitmap.Dispose();\r
364                         }\r
365                         base.Dispose (disposing);\r
366                 }\r
367
368                 #endregion      // Protected Instance Methods
369
370                 #region Events
371                 [Category("Action")]
372                 public event EventHandler       Click;
373
374                 [Category("Action")]
375                 public event EventHandler       DoubleClick;
376
377                 public event MouseEventHandler  MouseDown;
378                 public event MouseEventHandler  MouseMove;
379                 public event MouseEventHandler  MouseUp;
380                 #endregion      // Events
381         }
382 }