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
30 using System.ComponentModel;
31 using System.ComponentModel.Design;
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;
43 private Bitmap icon_bitmap;
46 private NotifyIconWindow window;
47 private bool systray_active;
48 private ToolTip tooltip;
49 #endregion // Local Variables
51 #region NotifyIconWindow Class
52 internal class NotifyIconWindow : Form {
56 public NotifyIconWindow(NotifyIcon owner) {
59 rect = new Rectangle(0, 0, 1, 1);
63 SizeChanged += new EventHandler(HandleSizeChanged);
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;
74 protected override CreateParams CreateParams {
78 cp = base.CreateParams;
80 cp.Parent = IntPtr.Zero;
81 cp.Style = (int)WindowStyles.WS_POPUP;
82 cp.Style |= (int)WindowStyles.WS_CLIPSIBLINGS;
84 cp.ExStyle = (int)(WindowExStyles.WS_EX_TOOLWINDOW);
90 protected override void WndProc(ref Message m) {
92 case Msg.WM_NCPAINT: {
93 PaintEventArgs paint_event;
95 paint_event = XplatUI.PaintEventStart(Handle, false);
96 OnPaintInternal (paint_event);
97 XplatUI.PaintEventEnd(Handle, false);
102 // NotifyIcon does CONTEXTMENU on mouse up, not down
103 // so we swallow the message here, and handle it on our own
105 case Msg.WM_CONTEXTMENU:
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));
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);
121 case Msg.WM_LBUTTONDBLCLK: {
122 HandleDoubleClick(this, EventArgs.Empty);
126 case Msg.WM_MOUSEMOVE: {
127 HandleMouseMove(this, new MouseEventArgs(MouseButtons.None, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
131 case Msg.WM_RBUTTONDOWN: {
132 HandleMouseDown(this, new MouseEventArgs(MouseButtons.Right, 1, Control.MousePosition.X, Control.MousePosition.Y, 0));
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);
142 case Msg.WM_RBUTTONDBLCLK: {
143 HandleDoubleClick(this, EventArgs.Empty);
150 base.WndProc (ref m);
153 internal void CalculateIconRect() {
154 if (owner != null && owner.icon != null) {
159 // Icons are always square. Try to center them in the window
160 if (ClientRectangle.Width < ClientRectangle.Height) {
161 size = ClientRectangle.Width;
163 size = ClientRectangle.Height;
165 x = this.ClientRectangle.Width / 2 - size / 2;
166 y = this.ClientRectangle.Height / 2 - size / 2;
167 rect = new Rectangle(x, y, size, size);
169 // Force our window to be square
174 if (Height != size) {
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);
188 internal void InternalRecreateHandle () {
189 base.RecreateHandle ();
193 private void HandleSizeChanged(object sender, EventArgs e) {
197 private void HandleClick(object sender, EventArgs e) {
198 if (owner.Click != null) {
199 owner.Click(owner, e);
203 private void HandleDoubleClick(object sender, EventArgs e) {
204 if (owner.DoubleClick != null) {
205 owner.DoubleClick(owner, e);
209 private void HandleMouseDown(object sender, MouseEventArgs e) {
210 if (owner.MouseDown != null) {
211 owner.MouseDown(owner, e);
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));
220 if (owner.MouseUp != null) {
221 owner.MouseUp(owner, e);
225 private void HandleMouseMove(object sender, MouseEventArgs e) {
226 if (owner.MouseMove != null) {
227 owner.MouseMove(owner, e);
231 #endregion // NotifyIconWindow Class
233 #region Public Constructors
234 public NotifyIcon() {
235 window = new NotifyIconWindow(this);
236 systray_active = false;
239 public NotifyIcon(System.ComponentModel.IContainer container) : this() {
241 #endregion // Public Constructors
243 #region Private Methods
244 private void ShowSystray(bool property_changed) {
245 if (property_changed) {
246 window.CalculateIconRect();
249 if (systray_active) {
250 if (property_changed) {
260 icon_bitmap = icon.ToBitmap();
262 systray_active = true;
263 XplatUI.SystrayAdd(window.Handle, text, icon, out tooltip);
266 private void HideSystray() {
267 if (!systray_active) {
271 systray_active = false;
272 XplatUI.SystrayRemove(window.Handle, ref tooltip);
275 private void UpdateSystray() {
276 if (icon_bitmap != null) {
277 icon_bitmap.Dispose();
281 icon_bitmap = icon.ToBitmap();
284 XplatUI.SystrayChange(window.Handle, text, icon, ref tooltip);
287 #endregion // Private Methods
289 #region Public Instance Properties
291 public ContextMenu ContextMenu {
297 if (context_menu != value) {
298 context_menu = value;
299 window.ContextMenu = value;
327 if (value.Length >= 64) {
328 throw new ArgumentException("ToolTip length must be less than 64 characters long", "Text");
331 if (text == string.Empty && icon == null) {
341 [DefaultValue(false)]
342 public bool Visible {
348 if (visible != value) {
351 // Let our control know, too
352 window.is_visible = value;
362 #endregion // Public Instance Properties
364 #region Protected Instance Methods
365 protected override void Dispose(bool disposing) {
366 if (icon_bitmap != null) {
367 icon_bitmap.Dispose();
373 base.Dispose (disposing);
376 #endregion // Protected Instance Methods
380 public event EventHandler Click;
383 public event EventHandler DoubleClick;
385 public event MouseEventHandler MouseDown;
386 public event MouseEventHandler MouseMove;
387 public event MouseEventHandler MouseUp;