New tests.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ToolTip.cs
index 21c6e126217102dff701ab759a72ab42ec0105c8..a5d4a7fea118bf6232e8af7ebf8aa4236c905465 100644 (file)
 //
 //
 
-
-// COMPLETE
-
 using System.Collections;
 using System.ComponentModel;
 using System.Drawing;
+using System.Drawing.Text;
 
 namespace System.Windows.Forms {
+#if NET_2_0
+       [DefaultEvent ("Popup")]
+#endif
        [ProvideProperty ("ToolTip", typeof(System.Windows.Forms.Control))]
        [ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Allow)]
        public
@@ -47,28 +48,42 @@ namespace System.Windows.Forms {
                internal int            re_show_delay;
                internal bool           show_always;
 
+               internal Color          back_color;
+               internal Color          fore_color;
+               
                internal ToolTipWindow  tooltip_window;                 // The actual tooltip window
                internal Hashtable      tooltip_strings;                // List of strings for each control, indexed by control
                internal ArrayList      controls;
                internal Control        active_control;                 // Control for which the tooltip is currently displayed
                internal Control        last_control;                   // last control the mouse was in
                internal Timer          timer;                          // Used for the various intervals
+               private Form            hooked_form;
+
+#if NET_2_0
+               private bool isBalloon;
+               private bool owner_draw;
+               private bool stripAmpersands;
+               private ToolTipIcon tool_tip_icon;
+               private bool useAnimation;
+               private bool useFading;
+               private object tag;
+#endif
+
                #endregion      // Local variables
 
                #region ToolTipWindow Class
                internal class ToolTipWindow : Control {
                        #region ToolTipWindow Class Local Variables
-                       internal StringFormat string_format;
+                       private Control associated_control;
+                       internal Icon icon;
+                       internal string title = String.Empty;
+                       internal Rectangle icon_rect;
+                       internal Rectangle title_rect;
+                       internal Rectangle text_rect;
                        #endregion      // ToolTipWindow Class Local Variables
-
+                       
                        #region ToolTipWindow Class Constructor
                        internal ToolTipWindow() {
-
-                               string_format = new StringFormat();
-                               string_format.LineAlignment = StringAlignment.Center;
-                               string_format.Alignment = StringAlignment.Center;
-                               string_format.FormatFlags = StringFormatFlags.NoWrap;
-
                                Visible = false;
                                Size = new Size(100, 20);
                                ForeColor = ThemeEngine.Current.ColorInfoText;
@@ -76,8 +91,18 @@ namespace System.Windows.Forms {
 
                                VisibleChanged += new EventHandler(ToolTipWindow_VisibleChanged);
 
+#if NET_2_0
+                               // UIA Framework: Used to generate UnPopup
+                               VisibleChanged += new EventHandler (OnUIAToolTip_VisibleChanged);
+#endif
+
                                SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
-                               SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
+                               SetStyle (ControlStyles.ResizeRedraw, true);
+                               if (ThemeEngine.Current.ToolTipTransparentBackground) {
+                                       SetStyle (ControlStyles.SupportsTransparentBackColor, true);
+                                       BackColor = Color.Transparent;
+                               } else
+                                       SetStyle (ControlStyles.Opaque, true);
                        }
 
                        #endregion      // ToolTipWindow Class Constructor
@@ -85,7 +110,7 @@ namespace System.Windows.Forms {
                        #region ToolTipWindow Class Protected Instance Methods
                        protected override void OnCreateControl() {
                                base.OnCreateControl ();
-                               XplatUI.SetTopmost(this.window.Handle, IntPtr.Zero, true);
+                               XplatUI.SetTopmost(this.window.Handle, true);
                        }
 
                        protected override CreateParams CreateParams {
@@ -107,16 +132,15 @@ namespace System.Windows.Forms {
                                // We don't do double-buffering on purpose:
                                // 1) we'd have to meddle with is_visible, it destroys the buffers if !visible
                                // 2) We don't draw much, no need to double buffer
-                               ThemeEngine.Current.DrawToolTip(pevent.Graphics, ClientRectangle, this);
-
                                base.OnPaint(pevent);
+
+                               OnDraw (new DrawToolTipEventArgs (pevent.Graphics, associated_control, associated_control, ClientRectangle, this.Text, this.BackColor, this.ForeColor, this.Font));
                        }
 
-                       protected override void Dispose(bool disposing) {
-                               if (disposing) {
-                                       this.string_format.Dispose();
-                               }
-                               base.Dispose (disposing);
+                       protected override void OnTextChanged (EventArgs args)
+                       {
+                               Invalidate ();
+                               base.OnTextChanged (args); 
                        }
 
                        protected override void WndProc(ref Message m) {
@@ -132,17 +156,82 @@ namespace System.Windows.Forms {
                        #endregion      // ToolTipWindow Class Protected Instance Methods
 
                        #region ToolTipWindow Class Private Methods
+                       internal virtual void OnDraw (DrawToolTipEventArgs e)
+                       {
+                               DrawToolTipEventHandler eh = (DrawToolTipEventHandler)(Events[DrawEvent]);
+                               if (eh != null)
+                                       eh (this, e);
+                               else
+                                       ThemeEngine.Current.DrawToolTip (e.Graphics, e.Bounds, this);
+                       }
+                       
+                       internal virtual void OnPopup (PopupEventArgs e)
+                       {
+                               PopupEventHandler eh = (PopupEventHandler)(Events[PopupEvent]);
+                               if (eh != null)
+                                       eh (this, e);
+                               else
+                                       e.ToolTipSize = ThemeEngine.Current.ToolTipSize (this, Text);
+                       }
+
                        private void ToolTipWindow_VisibleChanged(object sender, EventArgs e) {
                                Control control = (Control)sender;
 
                                if (control.is_visible) {
-                                       XplatUI.SetTopmost(control.window.Handle, IntPtr.Zero, true);
+                                       XplatUI.SetTopmost(control.window.Handle, true);
                                } else {
-                                       XplatUI.SetTopmost(control.window.Handle, IntPtr.Zero, false);
+                                       XplatUI.SetTopmost(control.window.Handle, false);
                                }
                        }
+#if NET_2_0
+
+                       // UIA Framework
+                       private void OnUIAToolTip_VisibleChanged (object sender, EventArgs e)
+                       {
+                               if (Visible == false) 
+                                       OnUnPopup (new PopupEventArgs (associated_control, associated_control, false, Size.Empty));
+                       }
+
+                       private void OnUnPopup (PopupEventArgs e)
+                       {
+                               PopupEventHandler eh = (PopupEventHandler) (Events [UnPopupEvent]);
+                               if (eh != null)
+                                       eh (this, e);
+                       }
+
+#endif
+
                        #endregion      // ToolTipWindow Class Protected Instance Methods
 
+                       #region Internal Properties
+                       internal override bool ActivateOnShow { get { return false; } }
+                       #endregion
+
+                       // This Present is used when we are using the expicit Show methods for 2.0.
+                       // It will not reposition the window.
+                       public void PresentModal (Control control, string text)
+                       {
+                               if (IsDisposed)
+                                       return;
+
+                               Size display_size;
+                               XplatUI.GetDisplaySize (out display_size);
+
+                               associated_control = control;
+
+                               Text = text;
+
+                               PopupEventArgs pea = new PopupEventArgs (control, control, false, Size.Empty);
+                               OnPopup (pea);
+
+                               if (pea.Cancel)
+                                       return;
+
+                               Size = pea.ToolTipSize;
+
+                               Visible = true;
+                       }
+               
                        public void Present (Control control, string text)
                        {
                                if (IsDisposed)
@@ -151,10 +240,22 @@ namespace System.Windows.Forms {
                                Size display_size;
                                XplatUI.GetDisplaySize (out display_size);
 
-                               Size size = ThemeEngine.Current.ToolTipSize (this, text);
+#if NET_2_0
+                               associated_control = control;
+#endif
+
+                               Text = text;
+
+                               PopupEventArgs pea = new PopupEventArgs (control, control, false, Size.Empty);
+                               OnPopup (pea);
+                               
+                               if (pea.Cancel)
+                                       return;
+                                       
+                               Size size = pea.ToolTipSize;
+
                                Width = size.Width;
                                Height = size.Height;
-                               Text = text;
 
                                int cursor_w, cursor_h, hot_x, hot_y;
                                XplatUI.GetCursorInfo (control.Cursor.Handle, out cursor_w, out cursor_h, out hot_x, out hot_y);
@@ -170,6 +271,34 @@ namespace System.Windows.Forms {
                                Location = loc;
                                Visible = true;
                        }
+
+
+                       #region Internal Events
+                       static object DrawEvent = new object ();
+                       static object PopupEvent = new object ();
+       
+#if NET_2_0
+                       // UIA Framework
+                       static object UnPopupEvent = new object ();
+#endif
+
+                       public event DrawToolTipEventHandler Draw {
+                               add { Events.AddHandler (DrawEvent, value); }
+                               remove { Events.RemoveHandler (DrawEvent, value); }
+                       }
+
+                       public event PopupEventHandler Popup {
+                               add { Events.AddHandler (PopupEvent, value); }
+                               remove { Events.RemoveHandler (PopupEvent, value); }
+                       }
+
+#if NET_2_0
+                       internal event PopupEventHandler UnPopup {
+                               add { Events.AddHandler (UnPopupEvent, value); }
+                               remove { Events.RemoveHandler (UnPopupEvent, value); }
+                       }
+#endif
+                       #endregion
                }
                #endregion      // ToolTipWindow Class
 
@@ -183,18 +312,83 @@ namespace System.Windows.Forms {
                        initial_delay = 500;
                        re_show_delay = 100;
                        show_always = false;
-
+                       back_color = SystemColors.Info;
+                       fore_color = SystemColors.InfoText;
+                       
+#if NET_2_0
+                       isBalloon = false;
+                       stripAmpersands = false;
+                       useAnimation = true;
+                       useFading = true;
+#endif
                        tooltip_strings = new Hashtable(5);
                        controls = new ArrayList(5);
 
                        tooltip_window = new ToolTipWindow();
                        tooltip_window.MouseLeave += new EventHandler(control_MouseLeave);
+                       tooltip_window.Draw += new DrawToolTipEventHandler (tooltip_window_Draw);
+                       tooltip_window.Popup += new PopupEventHandler (tooltip_window_Popup);
+
+#if NET_2_0
+                       // UIA Framework: Static event handlers
+                       tooltip_window.UnPopup += delegate (object sender, PopupEventArgs args) {
+                               OnUnPopup (args);
+                       };
+                       UnPopup += new PopupEventHandler (OnUIAUnPopup);
+#endif
 
                        timer = new Timer();
                        timer.Enabled = false;
                        timer.Tick +=new EventHandler(timer_Tick);
+
                }
 
+
+               #region UIA Framework: Events, Delegates and Methods
+#if NET_2_0
+               // NOTE: 
+               //      We are using Reflection to add/remove internal events.
+               //      Class ToolTipListener uses the events.
+               //
+               //      - UIAUnPopup. Event used to generate ChildRemoved in ToolTip
+               //      - UIAToolTipHookUp. Event used to keep track of associated controls
+               //      - UIAToolTipUnhookUp. Event used to remove track of associated controls
+               static object UnPopupEvent = new object ();
+
+               internal event PopupEventHandler UnPopup {
+                       add { Events.AddHandler (UnPopupEvent, value); }
+                       remove { Events.RemoveHandler (UnPopupEvent, value); }
+               }
+
+               internal static event PopupEventHandler UIAUnPopup;
+               internal static event ControlEventHandler UIAToolTipHookUp;
+               internal static event ControlEventHandler UIAToolTipUnhookUp;
+
+               internal Rectangle UIAToolTipRectangle {
+                       get { return tooltip_window.Bounds; }
+               }
+
+               internal static void OnUIAUnPopup (object sender, PopupEventArgs args)
+               {
+                       if (UIAUnPopup != null)
+                               UIAUnPopup (sender, args);
+               }
+
+               internal static void OnUIAToolTipHookUp (object sender, ControlEventArgs args)
+               {
+                       if (UIAToolTipHookUp != null)
+                               UIAToolTipHookUp (sender, args);
+               }
+
+               internal static void OnUIAToolTipUnhookUp (object sender, ControlEventArgs args)
+               {
+                       if (UIAToolTipUnhookUp != null)
+                               UIAToolTipUnhookUp (sender, args);
+               }
+
+#endif 
+               #endregion
+
                public ToolTip(System.ComponentModel.IContainer cont) : this() {
                        cont.Add (this);
                }
@@ -252,6 +446,21 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("Color [Info]")]
+               public Color BackColor {
+                       get { return this.back_color; }
+                       set { this.back_color = value; tooltip_window.BackColor = value; }
+               }
+
+               [DefaultValue ("Color [InfoText]")]
+               public Color ForeColor
+               {
+                       get { return this.fore_color; }
+                       set { this.fore_color = value; tooltip_window.ForeColor = value; }
+               }
+#endif
+
                [RefreshProperties (RefreshProperties.All)]
                public int InitialDelay {
                        get {
@@ -265,6 +474,14 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue (false)]
+               public bool OwnerDraw {
+                       get { return this.owner_draw; }
+                       set { this.owner_draw = value; }
+               }
+#endif
+
                [RefreshProperties (RefreshProperties.All)]
                public int ReshowDelay {
                        get {
@@ -290,16 +507,111 @@ namespace System.Windows.Forms {
                                }
                        }
                }
+
+
+#if NET_2_0
+               [DefaultValue (false)]
+               public bool IsBalloon {
+                       get { return isBalloon; }
+                       set { isBalloon = value; }
+               }
+
+               [Browsable (true)]
+               [DefaultValue (false)]
+               public bool StripAmpersands {
+                       get { return stripAmpersands; }
+                       set { stripAmpersands = value; }
+               }
+
+               [Localizable (false)]
+               [Bindable (true)]
+               [TypeConverter (typeof (StringConverter))]
+               [DefaultValue (null)]
+               public object Tag {
+                       get { return tag; }
+                       set { tag = value; }
+               }
+
+               [DefaultValue (ToolTipIcon.None)]
+               public ToolTipIcon ToolTipIcon {
+                       get { return this.tool_tip_icon; }
+                       set {
+                               switch (value) {
+                                       case ToolTipIcon.None:
+                                               tooltip_window.icon = null;
+                                               break;
+                                       case ToolTipIcon.Error:
+                                               tooltip_window.icon = SystemIcons.Error;
+                                               break;
+                                       case ToolTipIcon.Warning:
+                                               tooltip_window.icon = SystemIcons.Warning;
+                                               break;
+                                       case ToolTipIcon.Info:
+                                               tooltip_window.icon = SystemIcons.Information;
+                                               break;
+                               }
+
+                               tool_tip_icon = value;
+                       }
+               }
+               
+               [DefaultValue ("")]
+               public string ToolTipTitle {
+                       get { return tooltip_window.title; }
+                       set {
+                              if (value == null)
+                                      value = String.Empty;
+                              
+                              tooltip_window.title = value; 
+                       }
+               }
+               
+               [Browsable (true)]
+               [DefaultValue (true)]
+               public bool UseAnimation {
+                       get { return useAnimation; }
+                       set { useAnimation = value; }
+               }
+
+               [Browsable (true)]
+               [DefaultValue (true)]
+               public bool UseFading {
+                       get { return useFading; }
+                       set { useFading = value; }
+               }
+#endif
+
                #endregion      // Public Instance Properties
 
+               #region Protected Properties
+#if NET_2_0
+               protected virtual CreateParams CreateParams
+               {
+                       get
+                       {
+                               CreateParams cp = new CreateParams ();
+
+                               cp.Style = 2;
+
+                               return cp;
+                       }
+               }
+#endif
+               #endregion
+
                #region Public Instance Methods
                public bool CanExtend(object target) {
                        return false;
                }
 
+#if NET_2_0
+               [Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design,
+                        "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
+#endif
                [Localizable (true)]
                [DefaultValue ("")]
-               public string GetToolTip(Control control) {
+               public string GetToolTip (Control control)
+               {
                        string tooltip = (string)tooltip_strings[control];
                        if (tooltip == null)
                                return "";
@@ -308,10 +620,20 @@ namespace System.Windows.Forms {
 
                public void RemoveAll() {
                        tooltip_strings.Clear();
+#if NET_2_0
+                       //UIA Framework: ToolTip isn't associated anymore
+                       foreach (Control control in controls)
+                               OnUIAToolTipUnhookUp (this, new ControlEventArgs (control));
+#endif
+
                        controls.Clear();
                }
 
                public void SetToolTip(Control control, string caption) {
+#if NET_2_0
+                       // UIA Framework
+                       OnUIAToolTipHookUp (this, new ControlEventArgs (control));
+#endif
                        tooltip_strings[control] = caption;
 
                        // no need for duplicates
@@ -319,26 +641,141 @@ namespace System.Windows.Forms {
                                control.MouseEnter += new EventHandler(control_MouseEnter);
                                control.MouseMove += new MouseEventHandler(control_MouseMove);
                                control.MouseLeave += new EventHandler(control_MouseLeave);
+                               control.MouseDown += new MouseEventHandler (control_MouseDown);
                                controls.Add(control);
                        }
                        
                        // if SetToolTip is called from a control and the mouse is currently over that control,
-                       // make sure that tooltip_window.Text gets updated
-                       if (caption != null && last_control == control) {
+                       // make sure that tooltip_window.Text gets updated if it's being shown,
+                       // or show the tooltip for it if is not
+                       if (active_control == control && caption != null && state == TipState.Show) {
                                Size size = ThemeEngine.Current.ToolTipSize(tooltip_window, caption);
                                tooltip_window.Width = size.Width;
                                tooltip_window.Height = size.Height;
                                tooltip_window.Text = caption;
-                       }
+                               timer.Stop ();
+                               timer.Start ();
+                       } else if (control.IsHandleCreated && MouseInControl (control, false))
+                               ShowTooltip (control);
                }
 
                public override string ToString() {
                        return base.ToString() + " InitialDelay: " + initial_delay + ", ShowAlways: " + show_always;
                }
+
+#if NET_2_0
+               public void Show (string text, IWin32Window window)
+               {
+                       Show (text, window, 0);
+               }
+
+               public void Show (string text, IWin32Window window, int duration)
+               {
+                       if (window == null)
+                               throw new ArgumentNullException ("window");
+                       if (duration < 0)
+                               throw new ArgumentOutOfRangeException ("duration", "duration cannot be less than zero");
+
+                       if (!Active)
+                               return;
+                               
+                       timer.Stop ();
+                       
+                       Control c = (Control)window;
+
+                       XplatUI.SetOwner (tooltip_window.Handle, c.TopLevelControl.Handle);
+                       
+                       // If the mouse is in the requested window, use that position
+                       // Else, center in the requested window
+                       if (c.ClientRectangle.Contains (c.PointToClient (Control.MousePosition))) {
+                               tooltip_window.Location = Control.MousePosition;
+                               tooltip_strings[c] = text;
+                               HookupControlEvents (c);
+                       }
+                       else
+                               tooltip_window.Location = c.PointToScreen (new Point (c.Width / 2, c.Height / 2));
+                       
+                       // We need to hide our tooltip if the form loses focus, is closed, or is minimized
+                       HookupFormEvents ((Form)c.TopLevelControl);
+                       
+                       tooltip_window.PresentModal ((Control)window, text);
+                       
+                       state = TipState.Show;
+                       
+                       if (duration > 0) {
+                               timer.Interval = duration;
+                               timer.Start ();
+                       }
+               }
+               
+               public void Show (string text, IWin32Window window, Point point)
+               {
+                       Show (text, window, point, 0);
+               }
+
+               public void Show (string text, IWin32Window window, int x, int y)
+               {
+                       Show (text, window, new Point (x, y), 0);
+               }
+               
+               public void Show (string text, IWin32Window window, Point point, int duration)
+               {
+                       if (window == null)
+                               throw new ArgumentNullException ("window");
+                       if (duration < 0)
+                               throw new ArgumentOutOfRangeException ("duration", "duration cannot be less than zero");
+
+                       if (!Active)
+                               return;
+
+                       timer.Stop ();
+
+                       Control c = (Control)window;
+                       
+                       Point display_point = c.PointToScreen (Point.Empty);
+                       display_point.X += point.X;
+                       display_point.Y += point.Y;
+
+                       XplatUI.SetOwner (tooltip_window.Handle, c.TopLevelControl.Handle);
+
+                       // We need to hide our tooltip if the form loses focus, is closed, or is minimized
+                       HookupFormEvents ((Form)c.TopLevelControl);
+
+                       tooltip_window.Location = display_point;
+                       tooltip_window.PresentModal ((Control)window, text);
+
+                       state = TipState.Show;
+                       
+                       if (duration > 0) {
+                               timer.Interval = duration;
+                               timer.Start ();
+                       }
+               }
+               
+               public void Show (string text, IWin32Window window, int x, int y, int duration)
+               {
+                       Show (text, window, new Point (x, y), duration);
+               }
+               
+               public
+#else
+               internal
+#endif
+               void Hide (IWin32Window win)
+               {
+                       timer.Stop ();
+                       state = TipState.Initial;
+
+                       UnhookFormEvents ();
+                       tooltip_window.Visible = false;
+               }
                #endregion      // Public Instance Methods
 
                #region Protected Instance Methods
                protected override void Dispose(bool disposing) {
+                       // call the base impl first to avoid conflicts with any parent's events
+                       base.Dispose (disposing);
+
                        if (disposing) {
                                // Mop up the mess; or should we wait for the GC to kick in?
                                timer.Stop();
@@ -349,12 +786,24 @@ namespace System.Windows.Forms {
 
                                tooltip_strings.Clear();
                                
+#if NET_2_0
+                               //UIA Framework: ToolTip isn't associated anymore
+                               foreach (Control control in controls)
+                                       OnUIAToolTipUnhookUp (this, new ControlEventArgs (control));
+#endif
                                controls.Clear();
                        }
                }
+
+#if NET_2_0
+               protected void StopTimer ()
+               {
+                       timer.Stop ();
+               }
+#endif
                #endregion      // Protected Instance Methods
 
-               enum TipState {
+               internal enum TipState {
                        Initial,
                        Show,
                        Down
@@ -363,37 +812,103 @@ namespace System.Windows.Forms {
                TipState state = TipState.Initial;
 
                #region Private Methods
-               private void control_MouseEnter(object sender, EventArgs e) 
+
+#if NET_2_0
+               private void HookupFormEvents (Form form)
+               {
+                       hooked_form = form;
+
+                       form.Deactivate += new EventHandler (Form_Deactivate);
+                       form.Closed += new EventHandler (Form_Closed);
+                       form.Resize += new EventHandler (Form_Resize);
+               }
+
+               private void HookupControlEvents (Control control)
+               {
+                       if (!controls.Contains (control)) {
+                               control.MouseEnter += new EventHandler (control_MouseEnter);
+                               control.MouseMove += new MouseEventHandler (control_MouseMove);
+                               control.MouseLeave += new EventHandler (control_MouseLeave);
+                               control.MouseDown += new MouseEventHandler (control_MouseDown);
+                               controls.Add (control);
+                       }
+               }
+
+               private void UnhookControlEvents (Control control)
+               {
+                       control.MouseEnter -= new EventHandler (control_MouseEnter);
+                       control.MouseMove -= new MouseEventHandler (control_MouseMove);
+                       control.MouseLeave -= new EventHandler (control_MouseLeave);
+                       control.MouseDown -= new MouseEventHandler (control_MouseDown);
+               }
+#endif
+               private void UnhookFormEvents ()
+               {
+                       if (hooked_form == null)
+                               return;
+
+                       hooked_form.Deactivate -= new EventHandler (Form_Deactivate);
+                       hooked_form.Closed -= new EventHandler (Form_Closed);
+                       hooked_form.Resize -= new EventHandler (Form_Resize);
+
+                       hooked_form = null;
+               }
+
+
+               private void Form_Resize (object sender, EventArgs e)
                {
-                       last_control = (Control)sender;
+                       Form f = (Form)sender;
+
+                       if (f.WindowState == FormWindowState.Minimized)
+                               tooltip_window.Visible = false;
+               }
+
+               private void Form_Closed (object sender, EventArgs e)
+               {
+                       tooltip_window.Visible = false;
+               }
+
+               private void Form_Deactivate (object sender, EventArgs e)
+               {
+                       tooltip_window.Visible = false;
+               }
+
+               internal void Present (Control control, string text)
+               {
+                       tooltip_window.Present (control, text);
+               }
+               
+               private void control_MouseEnter (object sender, EventArgs e) 
+               {
+                       ShowTooltip (sender as Control);
+               }
+
+               private void ShowTooltip (Control control) 
+               {
+                       last_control = control;
 
                        // Whatever we're displaying right now, we don't want it anymore
                        tooltip_window.Visible = false;
                        timer.Stop();
                        state = TipState.Initial;
 
-                       // if we're in the same control as before (how'd that happen?) or if we're not active, leave
-                       if (!is_active || (active_control == (Control)sender)) {
+                       if (!is_active)
                                return;
-                       }
 
-                       if (!show_always) {
-                               IContainerControl cc = last_control.GetContainerControl ();
-                               if ((cc == null) || (cc.ActiveControl == null)) {
-                                       return;
-                               }
-                       }
+                       // ShowAlways controls whether the controls in non-active forms
+                       // can display its tooltips, even if they are not current active control.
+                       if (!show_always && control.FindForm () != Form.ActiveForm)
+                               return;
 
-                       string text = (string)tooltip_strings[sender];
+                       string text = (string)tooltip_strings[control];
                        if (text != null && text.Length > 0) {
-
                                if (active_control == null) {
-                                       timer.Interval = initial_delay;
+                                       timer.Interval = Math.Max (initial_delay, 1);
                                } else {
-                                       timer.Interval = re_show_delay;
+                                       timer.Interval = Math.Max (re_show_delay, 1);
                                }
 
-                               active_control = (Control)sender;
+                               active_control = control;
                                timer.Start ();
                        }
                }
@@ -421,8 +936,23 @@ namespace System.Windows.Forms {
                        }
                }
 
+               private void tooltip_window_Popup (object sender, PopupEventArgs e)
+               {
+                       e.ToolTipSize = ThemeEngine.Current.ToolTipSize (tooltip_window, tooltip_window.Text);
+                       OnPopup (e);
+               }
 
-               private bool MouseInControl(Control control) {
+               private void tooltip_window_Draw (object sender, DrawToolTipEventArgs e)
+               {
+#if NET_2_0
+                       if (OwnerDraw)
+                               OnDraw (e);
+                       else
+#endif
+                               ThemeEngine.Current.DrawToolTip (e.Graphics, e.Bounds, tooltip_window);
+               }
+               
+               private bool MouseInControl (Control control, bool fuzzy) {
                        Point   m;
                        Point   c;
                        Size    cw;
@@ -433,29 +963,62 @@ namespace System.Windows.Forms {
 
                        m = Control.MousePosition;
                        c = new Point(control.Bounds.X, control.Bounds.Y);
-                       if (control.parent != null) {
-                               c = control.parent.PointToScreen(c);
+                       if (control.Parent != null) {
+                               c = control.Parent.PointToScreen(c);
                        }
                        cw = control.ClientSize;
 
-                       if (c.X<=m.X && m.X<(c.X+cw.Width) &&
-                               c.Y<=m.Y && m.Y<(c.Y+cw.Height)) {
-                               return true;
-                       }
-                       return false;
+
+                       Rectangle rect = new Rectangle (c, cw);
+                       
+                       //
+                       // We won't get mouse move events on all platforms with the exact same
+                       // frequency, so cheat a bit.
+                       if (fuzzy)
+                               rect.Inflate (2, 2);
+
+                       return rect.Contains (m);
                }
 
-               private void control_MouseLeave(object sender, EventArgs e) {
+               private void control_MouseLeave(object sender, EventArgs e) 
+               {
+                       timer.Stop ();
+
+                       active_control = null;
+                       tooltip_window.Visible = false;
+
+                       if (last_control == sender)
+                               last_control = null;
+               }
+
+
+               void control_MouseDown (object sender, MouseEventArgs e)
+               {
+                       timer.Stop();
+
+                       active_control = null;
+                       tooltip_window.Visible = false;
+                       
+                       if (last_control == sender)
+                               last_control = null;
+               }
+
+#if NET_2_0
+/*
+               private void Hide (Control sender)
+               {
                        timer.Stop();
 
-                       if (!MouseInControl(tooltip_window) && !MouseInControl(active_control)) {
+                       if (!MouseInControl (tooltip_window, true) && !MouseInControl (active_control, true)) {
                                active_control = null;
                                tooltip_window.Visible = false;
                        }
                        
-                       if (last_control == (Control)sender)
+                       if (last_control == sender)
                                last_control = null;
                }
+*/
+#endif
 
                private void control_MouseMove(object sender, MouseEventArgs e) {
                        if (state != TipState.Down) {
@@ -463,6 +1026,54 @@ namespace System.Windows.Forms {
                                timer.Start();
                        }
                }
+
+               internal void OnDraw (DrawToolTipEventArgs e)
+               {
+                       DrawToolTipEventHandler eh = (DrawToolTipEventHandler)(Events[DrawEvent]);
+                       if (eh != null)
+                               eh (this, e);
+               }
+
+               internal void OnPopup (PopupEventArgs e)
+               {
+                       PopupEventHandler eh = (PopupEventHandler) (Events [PopupEvent]);
+                       if (eh != null)
+                               eh (this, e);
+               }
+
+#if NET_2_0
+               internal void OnUnPopup (PopupEventArgs e)
+               {
+                       PopupEventHandler eh = (PopupEventHandler) (Events [UnPopupEvent]);
+                       if (eh != null)
+                               eh (this, e);
+               }
+#endif
+               
+               internal bool Visible {
+                       get { return tooltip_window.Visible; }
+               }
                #endregion      // Private Methods
+
+               #region Events
+               static object PopupEvent = new object ();
+               static object DrawEvent = new object ();
+               
+#if NET_2_0
+               public
+#endif         
+               event PopupEventHandler Popup {
+                       add { Events.AddHandler (PopupEvent, value); }
+                       remove { Events.RemoveHandler (PopupEvent, value); }
+               }
+
+#if NET_2_0
+               public
+#endif
+               event DrawToolTipEventHandler Draw {
+                       add { Events.AddHandler (DrawEvent, value); }
+                       remove { Events.RemoveHandler (DrawEvent, value); }
+               }
+               #endregion
        }
 }