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:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
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.
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
23 // Peter Bartok pbartok@novell.com
28 using System.ComponentModel;
29 using System.ComponentModel.Design;
31 using System.Drawing.Text;
33 namespace System.Windows.Forms {
34 [DefaultProperty("Text")]
36 [DefaultEvent("MouseDoubleClick")]
38 [DefaultEvent("MouseDown")]
40 [Designer ("System.Windows.Forms.Design.NotifyIconDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
41 [ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Allow)]
42 public sealed class NotifyIcon : Component {
43 #region Local Variables
44 private ContextMenu context_menu;
46 private Bitmap icon_bitmap;
49 private NotifyIconWindow window;
50 private bool systray_active;
51 private ToolTip tooltip;
53 private string balloon_text;
54 private string balloon_title;
55 private ToolTipIcon balloon_icon;
56 private ContextMenuStrip context_menu_strip;
59 #endregion // Local Variables
61 #region NotifyIconWindow Class
62 internal class NotifyIconWindow : Form {
66 public NotifyIconWindow(NotifyIcon owner) {
69 rect = new Rectangle(0, 0, 1, 1);
71 FormBorderStyle = FormBorderStyle.None;
75 SizeChanged += new EventHandler(HandleSizeChanged);
77 // Events that need to be sent to our parent
78 Click += new EventHandler(HandleClick);
79 DoubleClick += new EventHandler(HandleDoubleClick);
80 MouseDown +=new MouseEventHandler(HandleMouseDown);
81 MouseUp +=new MouseEventHandler(HandleMouseUp);
82 MouseMove +=new MouseEventHandler(HandleMouseMove);
83 ContextMenu = owner.context_menu;
85 ContextMenuStrip = owner.context_menu_strip;
89 protected override CreateParams CreateParams {
93 cp = base.CreateParams;
95 cp.Parent = IntPtr.Zero;
96 cp.Style = (int)WindowStyles.WS_POPUP;
97 cp.Style |= (int)WindowStyles.WS_CLIPSIBLINGS;
99 cp.ExStyle = (int)(WindowExStyles.WS_EX_TOOLWINDOW);
105 protected override void WndProc(ref Message m) {
108 // NotifyIcon does CONTEXTMENU on mouse up, not down
109 // so we swallow the message here, and handle it on our own
111 case Msg.WM_CONTEXTMENU:
115 switch ((Msg)m.LParam.ToInt32()) {
116 case Msg.WM_LBUTTONDOWN: {
117 owner.OnMouseDown (new MouseEventArgs(MouseButtons.Left, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
121 case Msg.WM_LBUTTONUP: {
122 owner.OnMouseUp (new MouseEventArgs(MouseButtons.Left, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
123 owner.OnClick (EventArgs.Empty);
127 case Msg.WM_LBUTTONDBLCLK: {
128 owner.OnDoubleClick (EventArgs.Empty);
132 case Msg.WM_MOUSEMOVE: {
133 owner.OnMouseMove (new MouseEventArgs(MouseButtons.None, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
137 case Msg.WM_RBUTTONDOWN: {
138 owner.OnMouseDown (new MouseEventArgs(MouseButtons.Right, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
142 case Msg.WM_RBUTTONUP: {
143 owner.OnMouseUp (new MouseEventArgs(MouseButtons.Right, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
144 owner.OnClick (EventArgs.Empty);
148 case Msg.WM_RBUTTONDBLCLK: {
149 owner.OnDoubleClick (EventArgs.Empty);
153 case Msg.NIN_BALLOONUSERCLICK: {
154 owner.OnBalloonTipClicked (EventArgs.Empty);
158 case Msg.NIN_BALLOONSHOW: {
159 owner.OnBalloonTipShown (EventArgs.Empty);
163 case Msg.NIN_BALLOONHIDE:
164 case Msg.NIN_BALLOONTIMEOUT: {
165 owner.OnBalloonTipClosed (EventArgs.Empty);
173 base.WndProc (ref m);
176 internal void CalculateIconRect() {
181 // Icons are always square. Try to center them in the window
182 if (ClientRectangle.Width < ClientRectangle.Height) {
183 size = ClientRectangle.Width;
185 size = ClientRectangle.Height;
187 x = this.ClientRectangle.Width / 2 - size / 2;
188 y = this.ClientRectangle.Height / 2 - size / 2;
189 rect = new Rectangle(x, y, size, size);
191 Bounds = new Rectangle (0, 0, size, size);
194 internal override void OnPaintInternal (PaintEventArgs e) {
195 if (owner.icon != null) {
196 e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(SystemColors.Window), rect);
197 e.Graphics.DrawImage(owner.icon_bitmap,
199 new Rectangle (0, 0, owner.icon_bitmap.Width, owner.icon_bitmap.Height),
205 internal void InternalRecreateHandle () {
206 base.RecreateHandle ();
210 private void HandleSizeChanged(object sender, EventArgs e) {
211 owner.Recalculate ();
214 private void HandleClick (object sender, EventArgs e)
219 private void HandleDoubleClick (object sender, EventArgs e)
221 owner.OnDoubleClick (e);
224 private void HandleMouseDown (object sender, MouseEventArgs e)
226 owner.OnMouseDown (e);
229 private void HandleMouseUp (object sender, MouseEventArgs e)
234 private void HandleMouseMove (object sender, MouseEventArgs e)
236 owner.OnMouseMove (e);
239 #endregion // NotifyIconWindow Class
241 #region NotifyIconBalloonWindow Class
243 internal class BalloonWindow : Form
245 private IntPtr owner;
248 private string title;
250 private ToolTipIcon icon;
252 public BalloonWindow (IntPtr owner)
256 StartPosition = FormStartPosition.Manual;
257 FormBorderStyle = FormBorderStyle.None;
260 MouseDown += new MouseEventHandler (HandleMouseDown);
262 timer = new Timer ();
263 timer.Enabled = false;
264 timer.Tick += new EventHandler (HandleTimer);
267 protected override void OnShown (EventArgs e)
273 protected override void OnPaint (PaintEventArgs e)
275 ThemeEngine.Current.DrawBalloonWindow (e.Graphics, ClientRectangle, this);
279 private void Recalculate ()
281 Rectangle rect = ThemeEngine.Current.BalloonWindowRect (this);
286 Height = rect.Height;
289 // To be used when we have a "close button" inside balloon.
290 //private void HandleClick (object sender, EventArgs e)
292 // XplatUI.SendMessage (owner, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONHIDE);
296 private void HandleMouseDown (object sender, MouseEventArgs e)
298 XplatUI.SendMessage (owner, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONUSERCLICK);
302 private void HandleTimer (object sender, EventArgs e)
305 XplatUI.SendMessage (owner, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONTIMEOUT);
309 internal StringFormat Format {
311 StringFormat format = new StringFormat ();
312 format.Alignment = StringAlignment.Near;
313 format.HotkeyPrefix = HotkeyPrefix.Hide;
319 public string Title {
320 get { return this.title; }
322 if (value == this.title)
331 get { return this.text; }
333 if (value == this.text)
342 get { return timer.Interval; }
344 // Some systems theres a limitiation in timeout, WinXP is between 10k and 30k.
346 timer.Interval = 10000;
347 else if (value > 30000)
348 timer.Interval = 30000;
350 timer.Interval = value;
355 #endregion // NotifyIconBalloonWindow Class
357 #region Public Constructors
358 public NotifyIcon() {
359 window = new NotifyIconWindow(this);
360 systray_active = false;
368 public NotifyIcon(System.ComponentModel.IContainer container) : this() {
370 #endregion // Public Constructors
372 #region Public Methods
374 public void ShowBalloonTip (int timeout)
376 ShowBalloonTip(timeout, balloon_title, balloon_text, balloon_icon);
379 public void ShowBalloonTip(int timeout, string title, string text, ToolTipIcon icon)
381 XplatUI.SystrayBalloon(window.Handle, timeout, title, text, icon);
384 #endregion Public Methods
386 #region Private Methods
388 private void OnBalloonTipClicked (EventArgs e)
390 EventHandler eh = (EventHandler)(Events [BalloonTipClickedEvent]);
395 private void OnBalloonTipClosed (EventArgs e)
397 EventHandler eh = (EventHandler)(Events [BalloonTipClosedEvent]);
402 private void OnBalloonTipShown (EventArgs e)
404 EventHandler eh = (EventHandler)(Events [BalloonTipShownEvent]);
409 private void OnClick (EventArgs e)
411 EventHandler eh = (EventHandler)(Events [ClickEvent]);
416 private void OnDoubleClick (EventArgs e)
418 EventHandler eh = (EventHandler)(Events [DoubleClickEvent]);
423 private void OnMouseDown (MouseEventArgs e)
425 MouseEventHandler eh = (MouseEventHandler)(Events [MouseDownEvent]);
430 private void OnMouseUp (MouseEventArgs e)
432 if ((e.Button & MouseButtons.Right) == MouseButtons.Right && context_menu != null)
433 context_menu.Show (window, new Point(e.X, e.Y));
435 else if ((e.Button & MouseButtons.Right) == MouseButtons.Right && context_menu_strip != null)
436 context_menu_strip.Show (window, new Point (e.X, e.Y), ToolStripDropDownDirection.AboveLeft);
439 MouseEventHandler eh = (MouseEventHandler)(Events [MouseUpEvent]);
444 private void OnMouseMove (MouseEventArgs e)
446 MouseEventHandler eh = (MouseEventHandler)(Events [MouseMoveEvent]);
451 private void Recalculate ()
453 window.CalculateIconRect ();
459 private void ShowSystray()
461 systray_active = true;
466 icon_bitmap = icon.ToBitmap();
468 XplatUI.SystrayAdd(window.Handle, text, icon, out tooltip);
471 private void HideSystray()
473 if (!systray_active) {
477 systray_active = false;
478 XplatUI.SystrayRemove(window.Handle, ref tooltip);
481 private void UpdateSystray()
483 if (icon_bitmap != null) {
484 icon_bitmap.Dispose();
488 icon_bitmap = icon.ToBitmap();
491 XplatUI.SystrayChange(window.Handle, text, icon, ref tooltip);
494 #endregion // Private Methods
496 #region Public Instance Properties
498 public ToolTipIcon BalloonTipIcon {
499 get { return this.balloon_icon; }
501 if (value == this.balloon_icon)
504 this.balloon_icon = value;
509 public string BalloonTipText {
510 get { return this.balloon_text; }
512 if (value == this.balloon_text)
515 this.balloon_text = value;
520 public string BalloonTipTitle {
521 get { return this.balloon_title; }
523 if (value == this.balloon_title)
526 this.balloon_title = value;
535 public ContextMenu ContextMenu {
541 if (context_menu != value) {
542 context_menu = value;
543 window.ContextMenu = value;
549 [DefaultValue (null)]
550 public ContextMenuStrip ContextMenuStrip {
551 get { return this.context_menu_strip; }
553 if (this.context_menu_strip != value) {
554 this.context_menu_strip = value;
555 window.ContextMenuStrip = value;
571 if (text == string.Empty && icon == null) {
582 [Localizable (false)]
584 [TypeConverter (typeof (StringConverter))]
585 [DefaultValue (null)]
587 get { return this.tag; }
588 set { this.tag = value; }
592 [Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design,
593 typeof (System.Drawing.Design.UITypeEditor))]
603 if (value.Length >= 64) {
604 throw new ArgumentException("ToolTip length must be less than 64 characters long", "Text");
607 if (text == string.Empty && icon == null) {
617 [DefaultValue(false)]
618 public bool Visible {
624 if (visible != value) {
627 // Let our control know, too
628 window.is_visible = value;
638 #endregion // Public Instance Properties
640 #region Protected Instance Methods
641 protected override void Dispose(bool disposing) {
645 if (icon_bitmap != null) {
646 icon_bitmap.Dispose();
652 base.Dispose (disposing);
655 #endregion // Protected Instance Methods
658 static object ClickEvent = new object ();
659 static object DoubleClickEvent = new object ();
660 static object MouseDownEvent = new object ();
661 static object MouseMoveEvent = new object ();
662 static object MouseUpEvent = new object ();
665 static object BalloonTipClickedEvent = new object ();
666 static object BalloonTipClosedEvent = new object ();
667 static object BalloonTipShownEvent = new object ();
669 [MWFCategory("Action")]
670 public event EventHandler BalloonTipClicked {
671 add { Events.AddHandler (BalloonTipClickedEvent, value); }
672 remove { Events.RemoveHandler (BalloonTipClickedEvent, value); }
675 [MWFCategory("Action")]
676 public event EventHandler BalloonTipClosed {
677 add { Events.AddHandler (BalloonTipClosedEvent, value); }
678 remove { Events.RemoveHandler (BalloonTipClosedEvent, value); }
681 [MWFCategory("Action")]
682 public event EventHandler BalloonTipShown {
683 add { Events.AddHandler (BalloonTipShownEvent, value); }
684 remove { Events.RemoveHandler (BalloonTipShownEvent, value); }
689 [MWFCategory("Action")]
693 public event EventHandler Click {
694 add { Events.AddHandler (ClickEvent, value); }
695 remove { Events.RemoveHandler (ClickEvent, value); }
699 [MWFCategory("Action")]
703 public event EventHandler DoubleClick {
704 add { Events.AddHandler (DoubleClickEvent, value); }
705 remove { Events.RemoveHandler (DoubleClickEvent, value); }
708 public event MouseEventHandler MouseDown {
709 add { Events.AddHandler (MouseDownEvent, value); }
710 remove { Events.RemoveHandler (MouseDownEvent, value); }
713 public event MouseEventHandler MouseMove {
714 add { Events.AddHandler (MouseMoveEvent, value); }
715 remove { Events.RemoveHandler (MouseMoveEvent, value); }
718 public event MouseEventHandler MouseUp {
719 add { Events.AddHandler (MouseUpEvent, value); }
720 remove { Events.RemoveHandler (MouseUpEvent, value); }