Properly update the combo box selected text when the current item is changed, and...
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / InternalWindowManager.cs
index e36929d56665d075b7e6c443bc005028ed557b30..ea58417925e84ceedb6e206a1c7e674b14f49e53 100644 (file)
@@ -32,41 +32,20 @@ using System.Runtime.InteropServices;
 
 namespace System.Windows.Forms {
 
-       internal class InternalWindowManager {
-
-               private static Color titlebar_color;
-
-               private Size MinTitleBarSize = new Size (115, 25);
-
+       internal abstract class InternalWindowManager {
+               private TitleButtons title_buttons;
                internal Form form;
 
-               internal TitleButton close_button;
-               internal TitleButton maximize_button;
-               internal TitleButton minimize_button;
-               protected Rectangle icon_rect;
-               
-               private TitleButton [] title_buttons = new TitleButton [3];
-               
                // moving windows
                internal Point start;
                internal State state;
+               protected Point clicked_point;
                private FormPos sizing_edge;
                internal Rectangle virtual_position;
 
-               private bool is_mouse_down_menu;
+               private Rectangle normal_bounds;
+               private Rectangle iconic_bounds;
                
-               public class TitleButton {
-                       public Rectangle Rectangle;
-                       public ButtonState State;
-                       public CaptionButton Caption;
-                       public EventHandler Clicked;
-
-                       public TitleButton (CaptionButton caption, EventHandler clicked)
-                       {
-                               Caption = caption;
-                               Clicked = clicked;
-                       }
-               }
 
                public enum State {
                        Idle,
@@ -96,44 +75,103 @@ namespace System.Windows.Forms {
 
                public InternalWindowManager (Form form)
                {
-                       titlebar_color = Color.FromArgb (255, 0, 0, 255);
                        this.form = form;
 
                        form.SizeChanged += new EventHandler (FormSizeChangedHandler);
 
-                       CreateButtons ();
+                       title_buttons = new TitleButtons (form);
+                       ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
                }
 
                public Form Form {
                        get { return form; }
                }
-
-               public Rectangle CloseButtonRect {
-                       get { return close_button.Rectangle; }
-                       set { close_button.Rectangle = value; }
+               
+               public int IconWidth {
+                       get { return TitleBarHeight - 5; }
                }
 
-               public Rectangle MinimizeButtonRect {
-                       get { return minimize_button.Rectangle; }
-                       set { minimize_button.Rectangle = value; }
+               public TitleButtons TitleButtons {
+                       get {
+                               return title_buttons;
+                       }
                }
-
-               public Rectangle MaximizeButtonRect {
-                       get { return maximize_button.Rectangle; }
-                       set { maximize_button.Rectangle = value; }
+               internal Rectangle NormalBounds {
+                       get {
+                               return normal_bounds;
+                       }
+                       set {
+                               normal_bounds = value;
+                       }
                }
-
-               public Rectangle IconRect {
-                       get { return icon_rect; }
-                       set { value = icon_rect; }
+               internal Size IconicSize {
+                       get {
+                               return SystemInformation.MinimizedWindowSize;
+                       }
+               }
+               
+               internal Rectangle IconicBounds {
+                       get {
+                               if (iconic_bounds == Rectangle.Empty)
+                                       return Rectangle.Empty;
+                               Rectangle result = iconic_bounds;
+                               result.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y;
+                               return result;
+                       }
+                       set {
+                               iconic_bounds = value;
+                               iconic_bounds.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y;
+                       }
                }
 
-               public int IconWidth {
-                       get { return TitleBarHeight - 5; }
+               internal virtual Rectangle MaximizedBounds {
+                       get {
+                               return Form.Parent.ClientRectangle;
+                       }
                }
+                               
+               public virtual void UpdateWindowState (FormWindowState old_window_state, FormWindowState new_window_state, bool force)
+               {
+                       if (old_window_state == FormWindowState.Normal) {
+                               NormalBounds = form.Bounds;
+                       } else if (old_window_state == FormWindowState.Minimized) {
+                               IconicBounds = form.Bounds;
+                       }
+
+                       switch (new_window_state) {
+                       case FormWindowState.Minimized:
+                               if (IconicBounds == Rectangle.Empty) {
+                                       Size size = IconicSize;
+                                       Point location = new Point (0, Form.Parent.ClientSize.Height - size.Height);
+                                       IconicBounds = new Rectangle (location, size);
+                               }
+                               form.Bounds = IconicBounds;
+                               break;
+                       case FormWindowState.Maximized:
+                               form.Bounds = MaximizedBounds;
+                               break;
+                       case FormWindowState.Normal:
+                               form.Bounds = NormalBounds;
+                               break;
+                       }
 
-               public virtual bool HandleMessage (ref Message m)
+                       UpdateWindowDecorations (new_window_state);
+                       form.ResetCursor ();
+               }
+               
+               public virtual void UpdateWindowDecorations (FormWindowState window_state)
+               {
+                       ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
+                       if (form.IsHandleCreated)
+                               XplatUI.RequestNCRecalc (form.Handle);
+               }
+               
+               public virtual bool WndProc (ref Message m)
                {
+#if debug
+                       Console.WriteLine(DateTime.Now.ToLongTimeString () + " " + this.GetType () .Name + " (Handle={0},Text={1}) received message {2}", form.IsHandleCreated ? form.Handle : IntPtr.Zero,  form.Text, m.ToString ());
+#endif
+
                        switch ((Msg)m.Msg) {
 
 
@@ -149,59 +187,21 @@ namespace System.Windows.Forms {
                                break;
 
                        case Msg.WM_RBUTTONDOWN:
+                               return HandleRButtonDown (ref m);
+                               
                        case Msg.WM_LBUTTONDOWN:
-                               return HandleButtonDown (ref m);
+                               return HandleLButtonDown (ref m);
+                               
+                       case Msg.WM_LBUTTONDBLCLK:
+                               return HandleLButtonDblClick (ref m);
+                               
                        case Msg.WM_PARENTNOTIFY:
                                if (Control.LowOrder(m.WParam.ToInt32()) == (int) Msg.WM_LBUTTONDOWN) 
                                        Activate ();
                                break;
-                               
-                       case Msg.WM_NCHITTEST:
-                               int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
-                               int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
 
-                               NCPointToClient (ref x, ref y);
-
-                               FormPos pos = FormPosForCoords (x, y);
-                               
-                               if (pos == FormPos.TitleBar) {
-                                       m.Result = new IntPtr ((int) HitTest.HTCAPTION);
-                                       return true;
-                               }
-
-                               if (!IsSizable)
-                                       return false;
-
-                               switch (pos) {
-                               case FormPos.Top:
-                                       m.Result = new IntPtr ((int) HitTest.HTTOP);
-                                       break;
-                               case FormPos.Left:
-                                       m.Result = new IntPtr ((int) HitTest.HTLEFT);
-                                       break;
-                               case FormPos.Right:
-                                       m.Result = new IntPtr ((int) HitTest.HTRIGHT);
-                                       break;
-                               case FormPos.Bottom:
-                                       m.Result = new IntPtr ((int) HitTest.HTBOTTOM);
-                                       break;
-                               case FormPos.TopLeft:
-                                       m.Result = new IntPtr ((int) HitTest.HTTOPLEFT);
-                                       break;
-                               case FormPos.TopRight:
-                                       m.Result = new IntPtr ((int) HitTest.HTTOPRIGHT);
-                                       break;
-                               case FormPos.BottomLeft:
-                                       m.Result = new IntPtr ((int) HitTest.HTBOTTOMLEFT);
-                                       break;
-                               case FormPos.BottomRight:
-                                       m.Result = new IntPtr ((int) HitTest.HTBOTTOMRIGHT);
-                                       break;
-                               default:
-                                       // We return false so that DefWndProc handles things
-                                       return false;
-                               }
-                               return true;
+                       case Msg.WM_NCHITTEST: 
+                               return HandleNCHitTest (ref m);
 
                                // Return true from these guys, otherwise win32 will mess up z-order
                        case Msg.WM_NCLBUTTONUP:
@@ -224,139 +224,168 @@ namespace System.Windows.Forms {
                                HandleNCMouseLeave (ref m);
                                break;
                        
-                       case Msg.WM_MOUSE_LEAVE:
-                               FormMouseLeave (ref m);
+                       case Msg.WM_MOUSELEAVE:
+                               HandleMouseLeave (ref m);
                                break;
 
                        case Msg.WM_NCCALCSIZE:
-                               XplatUIWin32.NCCALCSIZE_PARAMS  ncp;
+                               return HandleNCCalcSize (ref m);
 
-                               if (m.WParam == (IntPtr) 1) {
-                                       ncp = (XplatUIWin32.NCCALCSIZE_PARAMS) Marshal.PtrToStructure (m.LParam,
-                                                       typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
+                       case Msg.WM_NCPAINT:
+                               return HandleNCPaint (ref m);
+                       }
 
-                                       int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
+                       return false;
+               }
 
-                                       if (HasBorders) {
-                                               ncp.rgrc1.top += TitleBarHeight + bw;
-                                               ncp.rgrc1.bottom -= bw;
-                                               ncp.rgrc1.left += bw;
-                                               ncp.rgrc1.right -= bw;
-                                       }
+               protected virtual bool HandleNCPaint (ref Message m)
+               {
+                       PaintEventArgs pe = XplatUI.PaintEventStart (ref m, form.Handle, false);
 
-                                       Marshal.StructureToPtr(ncp, m.LParam, true);
-                               }
+                       Rectangle clip;
+                       
+                       if (form.ActiveMenu != null) {
+                               Point pnt;
 
-                               break;
+                               pnt = GetMenuOrigin ();
 
-                       case Msg.WM_NCPAINT:
-                               PaintEventArgs pe = XplatUI.PaintEventStart (form.Handle, false);
-
-                               Rectangle clip;
-                               // clip region is not correct on win32.
-                               // if (m.WParam.ToInt32 () > 1) {
-                               //      Region r = Region.FromHrgn (m.WParam);
-                               //      RectangleF rf = r.GetBounds (pe.Graphics);
-                               //      clip = new Rectangle ((int) rf.X, (int) rf.Y, (int) rf.Width, (int) rf.Height);
-                               //} else {      
-                               clip = new Rectangle (0, 0, form.Width, form.Height);
-                               //}
+                               // The entire menu has to be in the clip rectangle because the 
+                               // control buttons are right-aligned and otherwise they would
+                               // stay painted when the window gets resized.
+                               clip = new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0);
+                               clip = Rectangle.Union (clip, pe.ClipRectangle);
+                               pe.SetClip (clip);
+                               pe.Graphics.SetClip (clip);
 
+                               form.ActiveMenu.Draw (pe, new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0));
+                       }
+                       if (HasBorders || IsMinimized && !(Form.IsMdiChild && IsMaximized)) {
+                               // clip region is not correct on win32.
+                               // use the entire form's area.
+                               clip = new Rectangle (0, 0, form.Width, form.Height);
                                ThemeEngine.Current.DrawManagedWindowDecorations (pe.Graphics, clip, this);
-                               XplatUI.PaintEventEnd (form.Handle, false);
-                               return true;
                        }
-
-                       return false;
+                       XplatUI.PaintEventEnd (ref m, form.Handle, false);
+                       return true;
                }
 
-               public virtual void UpdateBorderStyle (FormBorderStyle border_style)
+               protected virtual bool HandleNCCalcSize (ref Message m)
                {
-                       XplatUI.SetBorderStyle (form.Handle, border_style);
+                       XplatUIWin32.NCCALCSIZE_PARAMS ncp;
+                       XplatUIWin32.RECT rect;
 
-                       if (ShouldRemoveWindowManager (border_style)) {
-                               form.RemoveWindowManager ();
-                               return;
-                       }
+                       if (m.WParam == (IntPtr)1) {
+                               ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (m.LParam,
+                                               typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
+                               
+                               ncp.rgrc1 = NCCalcSize (ncp.rgrc1);
+
+                               Marshal.StructureToPtr (ncp, m.LParam, true);
+                       } else {
+                               rect = (XplatUIWin32.RECT) Marshal.PtrToStructure (m.LParam, typeof (XplatUIWin32.RECT));
                                
-                       CreateButtons ();
+                               rect = NCCalcSize (rect);
+                               
+                               Marshal.StructureToPtr (rect, m.LParam, true);
+                       }
+                       
+                       return true;
                }
 
-               public bool HandleMenuMouseDown (MainMenu menu, int x, int y)
+               protected virtual XplatUIWin32.RECT NCCalcSize (XplatUIWin32.RECT proposed_window_rect)
                {
-                       Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
+                       int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
 
-                       is_mouse_down_menu = false;
-                       foreach (TitleButton button in title_buttons) {
-                               if (button != null) {
-                                       if (button.Rectangle.Contains (pt)) {
-                                               button.State = ButtonState.Pushed;
-                                               is_mouse_down_menu = true;
-                                       } else {
-                                               button.State = ButtonState.Normal;
-                                       }
+                       if (HasBorders) {
+                               proposed_window_rect.top += TitleBarHeight + bw;
+                               proposed_window_rect.bottom -= bw;
+                               proposed_window_rect.left += bw;
+                               proposed_window_rect.right -= bw;
+                       }
+
+                       if (XplatUI.RequiresPositiveClientAreaSize) {
+                               // This is necessary for Linux, can't handle <= 0-sized 
+                               // client areas correctly.
+                               if (proposed_window_rect.right <= proposed_window_rect.left) {
+                                       proposed_window_rect.right += proposed_window_rect.left - proposed_window_rect.right + 1;
+                               }
+                               if (proposed_window_rect.top >= proposed_window_rect.bottom) {
+                                       proposed_window_rect.bottom += proposed_window_rect.top - proposed_window_rect.bottom + 1;
                                }
                        }
-                       XplatUI.InvalidateNC (menu.GetForm().Handle);
-                       return is_mouse_down_menu;
+
+                       return proposed_window_rect;
                }
 
-               public void HandleMenuMouseUp (MainMenu menu, int x, int y)
+               protected virtual bool HandleNCHitTest (ref Message m)
                {
-                       Point pt = MenuTracker.ScreenToMenu (menu, new Point(x, y));
 
-                       foreach (TitleButton button in title_buttons) {
-                               if (button != null) {
-                                       if (button.Rectangle.Contains (pt)) {
-                                               button.Clicked (this, EventArgs.Empty);
-                                               button.State = ButtonState.Pushed;
-                                       } else {
-                                               button.State = ButtonState.Normal;
-                                       }
-                               }
+                       int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
+                       int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
+
+                       NCPointToClient (ref x, ref y);
+
+                       FormPos pos = FormPosForCoords (x, y);
+
+                       if (pos == FormPos.TitleBar) {
+                               m.Result = new IntPtr ((int)HitTest.HTCAPTION);
+                               return true;
                        }
-                       XplatUI.InvalidateNC (menu.GetForm().Handle);
-                       is_mouse_down_menu = false;
-                       return;
-               }
-               
-               public void HandleMenuMouseLeave(MainMenu menu, int x, int y)
-               {
-                       foreach (TitleButton button in title_buttons) {
-                               if (button != null) {
-                                       button.State = ButtonState.Normal;
-                               }
+
+                       if (!IsSizable)
+                               return false;
+
+                       switch (pos) {
+                       case FormPos.Top:
+                               m.Result = new IntPtr ((int)HitTest.HTTOP);
+                               break;
+                       case FormPos.Left:
+                               m.Result = new IntPtr ((int)HitTest.HTLEFT);
+                               break;
+                       case FormPos.Right:
+                               m.Result = new IntPtr ((int)HitTest.HTRIGHT);
+                               break;
+                       case FormPos.Bottom:
+                               m.Result = new IntPtr ((int)HitTest.HTBOTTOM);
+                               break;
+                       case FormPos.TopLeft:
+                               m.Result = new IntPtr ((int)HitTest.HTTOPLEFT);
+                               break;
+                       case FormPos.TopRight:
+                               m.Result = new IntPtr ((int)HitTest.HTTOPRIGHT);
+                               break;
+                       case FormPos.BottomLeft:
+                               m.Result = new IntPtr ((int)HitTest.HTBOTTOMLEFT);
+                               break;
+                       case FormPos.BottomRight:
+                               m.Result = new IntPtr ((int)HitTest.HTBOTTOMRIGHT);
+                               break;
+                       default:
+                               // We return false so that DefWndProc handles things
+                               return false;
                        }
-                       XplatUI.InvalidateNC (menu.GetForm().Handle);
-                       return;
+                       return true;
                }
-               
-               public void HandleMenuMouseMove (MainMenu menu, int x, int y)
+
+               public virtual void UpdateBorderStyle (FormBorderStyle border_style)
                {
-                       Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
-                       
-                       if (!is_mouse_down_menu)
+                       if (form.IsHandleCreated) {
+                               XplatUI.SetBorderStyle (form.Handle, border_style);
+                       }
+
+                       if (ShouldRemoveWindowManager (border_style)) {
+                               form.RemoveWindowManager ();
                                return;
-                               
-                       bool any_change = false;
-                       foreach (TitleButton button in title_buttons) {
-                               if (button == null) 
-                                       continue;
-                               
-                               if (button.Rectangle.Contains(pt)) {
-                                       any_change |= button.State != ButtonState.Pushed;
-                                       button.State = ButtonState.Pushed;
-                               } else {
-                                       any_change |= button.State != ButtonState.Normal;
-                                       button.State = ButtonState.Normal;
-                               }
                        }
-                       if (any_change)
-                               XplatUI.InvalidateNC (menu.GetForm().Handle);
+                               
+                       ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
                }
+
+               
                
                public virtual void SetWindowState (FormWindowState old_state, FormWindowState window_state)
                {
+                       UpdateWindowState (old_state, window_state, false);
                }
 
                public virtual FormWindowState GetWindowState ()
@@ -391,69 +420,67 @@ namespace System.Windows.Forms {
                        return style != FormBorderStyle.FixedToolWindow && style != FormBorderStyle.SizableToolWindow;
                }
 
-               protected virtual void Activate ()
+               public bool IconRectangleContains (int x, int y)
                {
-                       // Hack to get a paint
-                       //NativeWindow.WndProc (form.Handle, Msg.WM_NCPAINT, IntPtr.Zero, IntPtr.Zero);
-                       form.Refresh ();
+                       if (!ShowIcon)
+                               return false;
+
+                       Rectangle icon = ThemeEngine.Current.ManagedWindowGetTitleBarIconArea (this);
+                       return icon.Contains (x, y);
+               }
+
+               public bool ShowIcon {
+                       get {
+                               if (!Form.ShowIcon)
+                                       return false;
+                               if (!HasBorders)
+                                       return false;
+                               if (IsMinimized)
+                                       return true;
+                               if (IsToolWindow || Form.FormBorderStyle == FormBorderStyle.FixedDialog)
+                                       return false;
+                               return true;
+                       }
                }
 
-               public virtual bool IsActive ()
+               protected virtual void Activate ()
                {
-                       return true;
+                       form.Invalidate (true);
+                       form.Update ();
+               }
+
+               public virtual bool IsActive {
+                       get {
+                               return true;
+                       }
                }
 
 
                private void FormSizeChangedHandler (object sender, EventArgs e)
                {
-                       ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
-                       Message m = new Message ();
-                       m.Msg = (int) Msg.WM_NCPAINT;
-                       m.HWnd = form.Handle;
-                       m.LParam = IntPtr.Zero;
-                       m.WParam = new IntPtr (1);
-                       XplatUI.SendMessage (ref m);
-               }
-
-               protected void CreateButtons ()
-               {
-                       switch (form.FormBorderStyle) {
-                       case FormBorderStyle.None:
-                               close_button = null;
-                               minimize_button = null;
-                               maximize_button = null;
-                               if (IsMaximized || IsMinimized)
-                                       goto case FormBorderStyle.Sizable;
-                               break;
-                       case FormBorderStyle.FixedToolWindow:
-                       case FormBorderStyle.SizableToolWindow:
-                               close_button = new TitleButton (CaptionButton.Close, new EventHandler (CloseClicked));
-                               if (IsMaximized || IsMinimized)
-                                       goto case FormBorderStyle.Sizable;
-                               break;
-                       case FormBorderStyle.FixedSingle:
-                       case FormBorderStyle.Fixed3D:
-                       case FormBorderStyle.FixedDialog:
-                       case FormBorderStyle.Sizable:
-                               close_button = new TitleButton (CaptionButton.Close, new EventHandler (CloseClicked));
-                               minimize_button = new TitleButton (CaptionButton.Minimize, new EventHandler (MinimizeClicked));
-                               maximize_button = new TitleButton (CaptionButton.Maximize, new EventHandler (MaximizeClicked));
-                               break;
+                       if (form.IsHandleCreated) {
+                               ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
+                               XplatUI.InvalidateNC (form.Handle);
                        }
-
-                       title_buttons [0] = close_button;
-                       title_buttons [1] = minimize_button;
-                       title_buttons [2] = maximize_button;
-
-                       ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
                }
 
-               protected virtual bool HandleButtonDown (ref Message m)
+               protected virtual bool HandleRButtonDown (ref Message m)
+               {
+                       Activate ();
+                       return false;
+               }
+               
+               protected virtual bool HandleLButtonDown (ref Message m)
                {
                        Activate ();
                        return false;
                }
 
+               protected virtual bool HandleLButtonDblClick(ref Message m)
+               {
+                       return false;
+               }
+               
                protected virtual bool HandleNCMouseLeave (ref Message m)
                {
                        int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
@@ -472,7 +499,6 @@ namespace System.Windows.Forms {
                
                protected virtual bool HandleNCMouseMove (ref Message m)
                {
-
                        int x = Control.LowOrder((int)m.LParam.ToInt32( ));
                        int y = Control.HighOrder((int)m.LParam.ToInt32( ));
 
@@ -480,10 +506,15 @@ namespace System.Windows.Forms {
                        FormPos pos = FormPosForCoords (x, y);
 
                        if (pos == FormPos.TitleBar) {
-                               HandleTitleBarMove (x, y);
+                               HandleTitleBarMouseMove (x, y);
                                return true;
                        }
 
+                       if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
+                               MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y, 0);
+                               form.ActiveMenu.OnMouseMove (form, mea);
+                       }
+
                        return true;
                        
                }
@@ -494,8 +525,6 @@ namespace System.Windows.Forms {
 
                        start = Cursor.Position;
                        virtual_position = form.Bounds;
-
-                       is_mouse_down_menu = false;
                        
                        int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
                        int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
@@ -504,6 +533,11 @@ namespace System.Windows.Forms {
                        NCPointToClient (ref x, ref y);
                        FormPos pos = FormPosForCoords (x, y);
                        
+                       if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
+                               MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y - TitleBarHeight, 0);
+                               form.ActiveMenu.OnMouseDown (form, mea);
+                       }
+                       
                        if (pos == FormPos.TitleBar) {
                                HandleTitleBarDown (x, y);
                                return true;
@@ -525,66 +559,56 @@ namespace System.Windows.Forms {
 
                protected virtual void HandleNCLButtonDblClick (ref Message m)
                {
+                       int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
+                       int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
+
+                       // Need to adjust because we are in NC land
+                       NCPointToClient (ref x, ref y);
+
+                       FormPos pos = FormPosForCoords (x, y);
+                       if (pos == FormPos.TitleBar || pos == FormPos.Top)
+                               HandleTitleBarDoubleClick (x, y);
+
+               }
+               
+               protected virtual void HandleTitleBarDoubleClick (int x, int y)
+               {
+               
                }
                
                protected virtual void HandleTitleBarLeave (int x, int y)
                {
-                       is_mouse_down_menu = false;
+                       title_buttons.MouseLeave (x, y);
                }
                
-               protected virtual void HandleTitleBarMove (int x, int y)
+               protected virtual void HandleTitleBarMouseMove (int x, int y)
                {
-                       if (!is_mouse_down_menu)
-                               return;
-                       
-                       bool any_change = false;
-                       foreach (TitleButton button in title_buttons) {
-                               if (button == null)
-                                       continue;
-                               
-                               if (button.Rectangle.Contains (x, y)) {
-                                       any_change |= button.State != ButtonState.Pushed;
-                                       button.State = ButtonState.Pushed;
-                               } else {
-                                       any_change |= button.State != ButtonState.Normal;
-                                       button.State = ButtonState.Normal;
-                               }
-                       }
-                       if (any_change)
+                       if (title_buttons.MouseMove (x, y))
                                XplatUI.InvalidateNC (form.Handle);
                }
                
                protected virtual void HandleTitleBarUp (int x, int y)
                {
-                       is_mouse_down_menu = false;
-                       
-                       foreach (TitleButton button in title_buttons) {
-                               if (button == null)
-                                       continue;
-                                       
-                               button.State = ButtonState.Normal;
-                               if (button.Rectangle.Contains (x, y)) {
-                                       button.Clicked (this, EventArgs.Empty);
-                               } 
-                       }
+                       title_buttons.MouseUp (x, y);
+
+                       return;
                }
                
                protected virtual void HandleTitleBarDown (int x, int y)
                {
-                       foreach (TitleButton button in title_buttons) {
-                               if (button != null && button.Rectangle.Contains (x, y)) {
-                                       button.State = ButtonState.Pushed;
-                                       XplatUI.InvalidateNC (form.Handle);
-                                       is_mouse_down_menu = true;
-                                       return;
+                       title_buttons.MouseDown (x, y);
+
+                       if (!TitleButtons.AnyPushedTitleButtons && !IsMaximized) {
+                               state = State.Moving;
+                               clicked_point = new Point (x, y);
+                               if (form.Parent != null) {
+                                       form.CaptureWithConfine (form.Parent);
+                               } else {
+                                       form.Capture = true;
                                }
                        }
-
-                       if (IsMaximized)
-                               return;
-
-                       state = State.Moving;
-                       form.Capture = true;
+                       
+                       XplatUI.InvalidateNC (form.Handle);
                }
 
                private bool HandleMouseMove (Form form, ref Message m)
@@ -597,31 +621,18 @@ namespace System.Windows.Forms {
                                HandleSizing (m);
                                return true;
                        }
-
-                       /*
-                       if (IsSizable) {
-                               int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
-                               int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
-                               FormPos pos = FormPosForCoords (x, y);
-                               Console.WriteLine ("position:   " + pos);
-                               SetCursorForPos (pos);
-
-                               ClearVirtualPosition ();
-                               state = State.Idle;
-                       }
-                       */
                        
                        return false;
                }
 
-               private void FormMouseLeave (ref Message m)
+               private void HandleMouseLeave (ref Message m)
                {
                        form.ResetCursor ();
                }
        
                protected virtual void HandleWindowMove (Message m)
                {
-                       Point move = MouseMove (m);
+                       Point move = MouseMove (Cursor.Position);
 
                        UpdateVP (virtual_position.X + move.X, virtual_position.Y + move.Y,
                                        virtual_position.Width, virtual_position.Height);
@@ -630,9 +641,17 @@ namespace System.Windows.Forms {
                private void HandleSizing (Message m)
                {
                        Rectangle pos = virtual_position;
-                       int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
-                       int mw = MinTitleBarSize.Width + (bw * 2);
-                       int mh = MinTitleBarSize.Height + (bw * 2);
+                       int mw;
+                       int mh;
+                       if (IsToolWindow) {
+                               int border_width = BorderWidth;
+                               mw = 2 * (border_width + Theme.ManagedWindowSpacingAfterLastTitleButton) + ThemeEngine.Current.ManagedWindowButtonSize (this).Width;
+                               mh = 2 * border_width + TitleBarHeight;
+                       } else {
+                               Size minimum_size = SystemInformation.MinWindowTrackSize;
+                               mw = minimum_size.Width;
+                               mh = minimum_size.Height;
+                       }
                        int x = Cursor.Position.X;
                        int y = Cursor.Position.Y;
 
@@ -694,7 +713,8 @@ namespace System.Windows.Forms {
                public bool IsToolWindow {
                        get {
                                if (form.FormBorderStyle == FormBorderStyle.SizableToolWindow ||
-                                               form.FormBorderStyle == FormBorderStyle.FixedToolWindow)
+                                   form.FormBorderStyle == FormBorderStyle.FixedToolWindow || 
+                                   form.GetCreateParams().IsSet (WindowExStyles.WS_EX_TOOLWINDOW))
                                        return true;
                                return false;
                        }
@@ -706,6 +726,18 @@ namespace System.Windows.Forms {
                        }
                }
 
+               public int BorderWidth {
+                       get {
+                               return ThemeEngine.Current.ManagedWindowBorderWidth (this);
+                       }
+               }
+               
+               public virtual int MenuHeight {
+                       get {
+                               return (form.Menu != null ? ThemeEngine.Current.MenuHeight : 0);
+                       }
+               }
+
                protected void UpdateVP (Rectangle r)
                {
                        UpdateVP (r.X, r.Y, r.Width, r.Height);
@@ -726,7 +758,7 @@ namespace System.Windows.Forms {
                        DrawVirtualPosition (virtual_position);
                }
 
-               private void HandleLButtonUp (ref Message m)
+               protected virtual void HandleLButtonUp (ref Message m)
                {
                        if (state == State.Idle)
                                return;
@@ -734,7 +766,10 @@ namespace System.Windows.Forms {
                        ClearVirtualPosition ();
 
                        form.Capture = false;
-                       form.Bounds = virtual_position;
+                       if (state == State.Moving && form.Location != virtual_position.Location) 
+                               form.Location = virtual_position.Location;
+                       else if (state == State.Sizing && form.Bounds != virtual_position)
+                               form.Bounds = virtual_position;
                        state = State.Idle;
 
                        OnWindowFinishedMoving ();
@@ -770,42 +805,16 @@ namespace System.Windows.Forms {
                        if (!button.Rectangle.IntersectsWith (clip))
                                return;
 
-                       dc.FillRectangle (SystemBrushes.Control, button.Rectangle);
-                       ControlPaint.DrawCaptionButton (dc, button.Rectangle,
-                                       button.Caption, button.State);
+                       ThemeEngine.Current.ManagedWindowDrawMenuButton (dc, button, clip, this);
                }
 
                public virtual void DrawMaximizedButtons (object sender, PaintEventArgs pe)
                {
                }
 
-               protected virtual void CloseClicked (object sender, EventArgs e)
+               protected Point MouseMove (Point pos)
                {
-                       form.Close ();
-               }
-
-               private void MinimizeClicked (object sender, EventArgs e)
-               {
-                       if (GetWindowState () != FormWindowState.Minimized) {
-                               form.WindowState = FormWindowState.Minimized;
-                       } else {
-                               form.WindowState = FormWindowState.Normal;
-                       }
-               }
-
-               private void MaximizeClicked (object sender, EventArgs e)
-               {
-                       if (GetWindowState () != FormWindowState.Maximized) {
-                               form.WindowState = FormWindowState.Maximized;
-                       } else {
-                               form.WindowState = FormWindowState.Normal;
-                       }
-               }
-
-               protected Point MouseMove (Message m)
-               {
-                       Point cp = Cursor.Position;
-                       return new Point (cp.X - start.X, cp.Y - start.Y);
+                       return new Point (pos.X - start.X, pos.Y - start.Y);
                }
 
                protected virtual void DrawVirtualPosition (Rectangle virtual_position)
@@ -825,13 +834,23 @@ namespace System.Windows.Forms {
 
                protected virtual void NCPointToClient(ref int x, ref int y) {
                        form.PointToClient(ref x, ref y);
-                       y += TitleBarHeight;
-                       y += ThemeEngine.Current.ManagedWindowBorderWidth (this);
+                       NCClientToNC (ref x, ref y);
                }
 
+               protected virtual void NCClientToNC (ref int x, ref int y) {
+                       y += TitleBarHeight;
+                       y += BorderWidth;
+                       y += MenuHeight;
+               }
+               
+               internal Point GetMenuOrigin ()
+               {
+                       return new Point (BorderWidth, BorderWidth + TitleBarHeight);
+               }
+               
                protected FormPos FormPosForCoords (int x, int y)
                {
-                       int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
+                       int bw = BorderWidth;
                        if (y < TitleBarHeight + bw) {
                                //      Console.WriteLine ("A");
                                if (y > bw && x > bw &&
@@ -876,6 +895,317 @@ namespace System.Windows.Forms {
                        return FormPos.None;
                }
        }
+       internal class TitleButton
+       {
+               public Rectangle Rectangle;
+               public ButtonState State;
+               public CaptionButton Caption;
+               private EventHandler Clicked;
+               public bool Visible;
+               bool entered;
+
+               public TitleButton (CaptionButton caption, EventHandler clicked)
+               {
+                       Caption = caption;
+                       Clicked = clicked;
+               }
+               
+               public void OnClick ()
+               {
+                       if (Clicked != null) {
+                               Clicked (this, EventArgs.Empty);
+                       }
+               }
+
+               public bool Entered {
+                       get { return entered; }
+                       set { entered = value; }
+               }
+       }
+
+       internal class TitleButtons : System.Collections.IEnumerable
+       {
+               public TitleButton MinimizeButton;
+               public TitleButton MaximizeButton;
+               public TitleButton RestoreButton;
+               public TitleButton CloseButton;
+               public TitleButton HelpButton;
+
+               public TitleButton [] AllButtons;
+               public bool Visible;
+
+               private ToolTip.ToolTipWindow tooltip;
+               private Timer tooltip_timer;
+               private TitleButton tooltip_hovered_button;
+               private TitleButton tooltip_hidden_button;
+               private const int tooltip_hide_interval = 3000;
+               private const int tooltip_show_interval = 1000;
+               private Form form;
+               
+               public TitleButtons (Form frm)
+               {
+                       this.form = frm;
+                       this.Visible = true;
+                       
+                       MinimizeButton = new TitleButton (CaptionButton.Minimize, new EventHandler (ClickHandler));
+                       MaximizeButton = new TitleButton (CaptionButton.Maximize, new EventHandler (ClickHandler));
+                       RestoreButton = new TitleButton (CaptionButton.Restore, new EventHandler (ClickHandler));
+                       CloseButton = new TitleButton (CaptionButton.Close, new EventHandler (ClickHandler));
+                       HelpButton = new TitleButton (CaptionButton.Help, new EventHandler (ClickHandler));
+
+                       AllButtons = new TitleButton [] { MinimizeButton, MaximizeButton, RestoreButton, CloseButton, HelpButton };
+               }
+               
+               private void ClickHandler (object sender, EventArgs e)
+               {
+                       if (!Visible) {
+                               return;
+                       }
+                       
+                       TitleButton button = (TitleButton) sender;
+                       
+                       switch (button.Caption) {
+                               case CaptionButton.Close: 
+                                       form.Close ();
+                                       break;
+                               case CaptionButton.Help:
+                                       Console.WriteLine ("Help not implemented.");
+                                       break;
+                               case CaptionButton.Maximize:
+                                       form.WindowState = FormWindowState.Maximized;
+                                       break;
+                               case CaptionButton.Minimize:
+                                       form.WindowState = FormWindowState.Minimized;
+                                       break;
+                               case CaptionButton.Restore:
+                                       form.WindowState = FormWindowState.Normal;
+                                       break;
+                       }
+               }
+               
+               public TitleButton FindButton (int x, int y)
+               {
+                       if (!Visible) {
+                               return null;
+                       }
+                       
+                       foreach (TitleButton button in AllButtons) {
+                               if (button.Visible && button.Rectangle.Contains (x, y)) {
+                                       return button;
+                               }
+                       }
+                       return null;
+               }
+               
+               public bool AnyPushedTitleButtons {
+                       get {
+                               if (!Visible) {
+                                       return false;
+                               }
+                               
+                               foreach (TitleButton button in AllButtons) {
+                                       if (button.Visible && button.State == ButtonState.Pushed) {
+                                               return true;
+                                       }
+                               }
+                               return false;
+                       }
+               }
+
+               #region IEnumerable Members
+
+               public System.Collections.IEnumerator GetEnumerator ()
+               {
+                       return AllButtons.GetEnumerator ();
+               }
+               #endregion
+
+               #region ToolTip helpers
+               // Called from MouseMove if mouse is over a button
+               public void ToolTipStart (TitleButton button)
+               {
+                       tooltip_hovered_button = button;
+
+                       if (tooltip_hovered_button == tooltip_hidden_button)
+                               return;
+                       tooltip_hidden_button = null;
+
+                       if (tooltip != null && tooltip.Visible)
+                               ToolTipShow (true);
+
+                       if (tooltip_timer == null) {
+
+                               tooltip_timer = new Timer ();
+                               tooltip_timer.Tick += new EventHandler (ToolTipTimerTick);
+                       }
+
+                       tooltip_timer.Interval = tooltip_show_interval;
+                       tooltip_timer.Start ();
+                       tooltip_hovered_button = button;
+               }
+
+               public void ToolTipTimerTick (object sender, EventArgs e)
+               {
+                       if (tooltip_timer.Interval == tooltip_hide_interval) {
+                               tooltip_hidden_button = tooltip_hovered_button;
+                               ToolTipHide (false);
+                       } else {
+                               ToolTipShow (false);
+                       }
+               }
+               // Called from timer (with only_refresh = false)
+               // Called from ToolTipStart if tooltip is already shown (with only_refresh = true)
+               public void ToolTipShow (bool only_refresh)
+               {
+                       if (!form.Visible)
+                               return;
+
+                       string text = Locale.GetText (tooltip_hovered_button.Caption.ToString ());
+
+                       tooltip_timer.Interval = tooltip_hide_interval;
+                       tooltip_timer.Enabled = true;
+
+                       if (only_refresh && (tooltip == null || !tooltip.Visible)) {
+                               return;
+                       }
+
+                       if (tooltip == null)
+                               tooltip = new ToolTip.ToolTipWindow ();
+                       else if (tooltip.Text == text && tooltip.Visible)
+                               return;
+                       else if (tooltip.Visible)
+                               tooltip.Visible = false;
+
+                       if (form.WindowState == FormWindowState.Maximized && form.MdiParent != null)
+                               tooltip.Present (form.MdiParent, text);
+                       else
+                               tooltip.Present (form, text);
+                       
+               }
+               
+               // Called from MouseLeave (with reset_hidden_button = true)
+               // Called from MouseDown  (with reset_hidden_button = false)
+               // Called from MouseMove if mouse isn't over any button (with reset_hidden_button = false)
+               // Called from Timer if hiding (with reset_hidden_button = false)
+               public void ToolTipHide (bool reset_hidden_button)
+               {
+                       if (tooltip_timer != null)
+                               tooltip_timer.Enabled = false;
+                       if (tooltip != null && tooltip.Visible)
+                               tooltip.Visible = false;
+                       if (reset_hidden_button)
+                               tooltip_hidden_button = null;
+               }
+               #endregion
+               
+               public bool MouseMove (int x, int y)
+               {
+                       if (!Visible) {
+                               return false;
+                       }
+
+                       bool any_change = false;
+                       bool any_pushed_buttons = AnyPushedTitleButtons;
+                       bool any_tooltip = false;
+                       TitleButton over_button = FindButton (x, y);
+
+                       foreach (TitleButton button in this) {
+                               if (button == null)
+                                       continue;
+                               
+                               if (button.State == ButtonState.Inactive)
+                                       continue;
+                                       
+                               if (button == over_button) {
+                                       if (any_pushed_buttons) {
+                                               any_change |= button.State != ButtonState.Pushed;
+                                               button.State = ButtonState.Pushed;
+                                       }
+                                       ToolTipStart (button);
+                                       any_tooltip = true;
+                                       if (!button.Entered) {
+                                               button.Entered = true;
+                                               if (ThemeEngine.Current.ManagedWindowTitleButtonHasHotElementStyle (button, form))
+                                                       any_change = true;
+                                       }
+                               } else {
+                                       if (any_pushed_buttons) {
+                                               any_change |= button.State != ButtonState.Normal;
+                                               button.State = ButtonState.Normal;
+                                       }
+                                       if (button.Entered) {
+                                               button.Entered = false;
+                                               if (ThemeEngine.Current.ManagedWindowTitleButtonHasHotElementStyle (button, form))
+                                                       any_change = true;
+                                       }
+                               }
+                       }
+
+                       if (!any_tooltip)
+                               ToolTipHide (false);
+
+                       return any_change;
+               }
+
+               public void MouseDown (int x, int y)
+               {
+                       if (!Visible) {
+                               return;
+                       }
+
+                       ToolTipHide (false);
+
+                       foreach (TitleButton button in this) {
+                               if (button != null && button.State != ButtonState.Inactive) {
+                                       button.State = ButtonState.Normal;
+                               }
+                       }
+                       TitleButton clicked_button = FindButton (x, y);
+                       if (clicked_button != null && clicked_button.State != ButtonState.Inactive) {
+                               clicked_button.State = ButtonState.Pushed;
+                       }
+               }
+
+               public void MouseUp (int x, int y)
+               {
+                       if (!Visible) {
+                               return;
+                       }
+                       
+                       TitleButton clicked_button = FindButton (x, y);
+                       if (clicked_button != null && clicked_button.State != ButtonState.Inactive) {
+                               clicked_button.OnClick ();
+                       }
+
+                       foreach (TitleButton button in this) {
+                               if (button == null || button.State == ButtonState.Inactive)
+                                       continue;
+
+                               button.State = ButtonState.Normal;
+                       }
+
+                       if (clicked_button == CloseButton && !form.closing)
+                               XplatUI.InvalidateNC (form.Handle);
+                               
+                       ToolTipHide (true);
+               }
+
+               internal void MouseLeave (int x, int y)
+               {
+                       if (!Visible) {
+                               return;
+                       }
+                       
+                       foreach (TitleButton button in this) {
+                               if (button == null || button.State == ButtonState.Inactive)
+                                       continue;
+
+                               button.State = ButtonState.Normal;
+                       }
+                       
+                       ToolTipHide (true);
+               }
+       }
 }