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