2007-03-26 Everaldo Canuto <everaldo@simios.org>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / XplatUIWin32.cs
index 6faee5e0b8b7105fac516be9edb0ad34c4326fed..61733946d1ea84ff799c3b760aa81e611ba52552 100644 (file)
@@ -63,6 +63,8 @@ namespace System.Windows.Forms {
                private static int              scroll_height;
                private static Hashtable        wm_nc_registered;
                private static RECT             clipped_cursor_rect;
+               private Hashtable               registered_classes;
+               private Hwnd HwndCreating; // the Hwnd we are currently creating (see CreateWindow)
 
                #endregion      // Local Variables
 
@@ -89,23 +91,67 @@ namespace System.Windows.Forms {
                        internal int            top;
                        internal int            right;
                        internal int            bottom;
-                       public override string ToString() {
+
+                       public RECT (int left, int top, int right, int bottom)
+                       {
+                               this.left = left;
+                               this.top = top;
+                               this.right = right;
+                               this.bottom = bottom;
+                       }
+
+                       #region Instance Properties
+                       public int Height { get { return bottom - top + 1; } }
+                       public int Width { get { return right - left + 1; } }
+                       public Size Size { get { return new Size (Width, Height); } }
+                       public Point Location { get { return new Point (left, top); } }
+                       #endregion
+
+                       #region Instance Methods
+                       public Rectangle ToRectangle ()
+                       {
+                               return Rectangle.FromLTRB (left, top, right, bottom);
+                       }
+
+                       public static RECT FromRectangle (Rectangle rectangle)
+                       {
+                               return new RECT (rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom);
+                       }
+
+                       public override int GetHashCode ()
+                       {
+                               return left ^ ((top << 13) | (top >> 0x13))
+                                 ^ ((Width << 0x1a) | (Width >> 6))
+                                 ^ ((Height << 7) | (Height >> 0x19));
+                       }
+                       
+                       public override string ToString ()
+                       {
                                return String.Format("RECT left={0}, top={1}, right={2}, bottom={3}, width={4}, height={5}", left, top, right, bottom, right-left, bottom-top);
                        }
+                       #endregion
 
-               }
+                       #region Operator overloads
+                       public static implicit operator Rectangle (RECT rect)
+                       {
+                               return Rectangle.FromLTRB (rect.left, rect.top, rect.right, rect.bottom);
+                       }
 
-               [StructLayout(LayoutKind.Sequential)]
-               internal struct POINT {
-                       internal int            x;
-                       internal int            y;
+                       public static implicit operator RECT (Rectangle rect)
+                       {
+                               return new RECT (rect.Left, rect.Top, rect.Right, rect.Bottom);
+                       }
+                       #endregion
                }
 
                internal enum SPIAction {
+                       SPI_GETKEYBOARDSPEED    = 0x000A,
+                       SPI_GETKEYBOARDDELAY    = 0x0016,
                        SPI_GETWORKAREA         = 0x0030,
                        SPI_GETMOUSEHOVERWIDTH  = 0x0062,
                        SPI_GETMOUSEHOVERHEIGHT = 0x0064,
                        SPI_GETMOUSEHOVERTIME   = 0x0066,
+                       SPI_GETWHEELSCROLLLINES = 0x0068
                }
 
                internal enum WindowPlacementFlags {
@@ -241,7 +287,9 @@ namespace System.Windows.Forms {
                        CS_BYTEALIGNCLIENT              = 0x00001000,
                        CS_BYTEALIGNWINDOW              = 0x00002000,
                        CS_GLOBALCLASS                  = 0x00004000,
-                       CS_IME                          = 0x00010000
+                       CS_IME                          = 0x00010000,
+                       // Windows XP+
+                       CS_DROPSHADOW                   = 0x00020000
                }
 
                internal enum SetWindowPosZOrder {
@@ -706,9 +754,6 @@ namespace System.Windows.Forms {
 
                #region Constructor & Destructor
                private XplatUIWin32() {
-                       WNDCLASS        wndClass;
-                       bool            result;
-
                        // Handle singleton stuff first
                        ref_count=0;
 
@@ -719,23 +764,7 @@ namespace System.Windows.Forms {
 
                        themes_enabled = false;
 
-                       // Prepare 'our' window class
-                       wnd_proc = new WndProc(NativeWindow.WndProc);
-                       wndClass.style = (int)(ClassStyle.CS_OWNDC | ClassStyle.CS_DBLCLKS);
-                       wndClass.lpfnWndProc = wnd_proc;
-                       wndClass.cbClsExtra = 0;
-                       wndClass.cbWndExtra = 0;
-                       wndClass.hbrBackground = IntPtr.Zero;
-                       wndClass.hCursor = Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW);
-                       wndClass.hIcon = IntPtr.Zero;
-                       wndClass.hInstance = IntPtr.Zero;
-                       wndClass.lpszClassName = XplatUI.DefaultClassName;
-                       wndClass.lpszMenuName = "";
-
-                       result=Win32RegisterClass(ref wndClass);
-                       if (result==false) {
-                               Win32MessageBox(IntPtr.Zero, "Could not register the "+XplatUI.DefaultClassName+" window class, win32 error " + Win32GetLastError().ToString(), "Oops", 0);
-                       }
+                       wnd_proc = new WndProc(InternalWndProc);
 
                        FosterParent=Win32CreateWindow((int)WindowExStyles.WS_EX_TOOLWINDOW, "static", "Foster Parent Window", (int)WindowStyles.WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
 
@@ -747,11 +776,48 @@ namespace System.Windows.Forms {
                        scroll_width = Win32GetSystemMetrics(SystemMetrics.SM_CXVSCROLL);
 
                        timer_list = new Hashtable ();
+                       registered_classes = new Hashtable ();
                }
                #endregion      // Constructor & Destructor
 
                #region Private Support Methods
 
+               private string RegisterWindowClass (int classStyle)
+               {
+                       string class_name;
+
+                       lock (registered_classes) {
+                               class_name = (string)registered_classes[classStyle];
+
+                               if (class_name != null)
+                                       return class_name;
+
+                               class_name = string.Format ("Mono.WinForms.{0}.{1}", System.Threading.Thread.GetDomainID ().ToString (), classStyle);
+
+                               WNDCLASS wndClass;
+
+                               wndClass.style = classStyle;
+                               wndClass.lpfnWndProc = wnd_proc;
+                               wndClass.cbClsExtra = 0;
+                               wndClass.cbWndExtra = 0;
+                               wndClass.hbrBackground = (IntPtr)(GetSysColorIndex.COLOR_WINDOW + 1);
+                               wndClass.hCursor = Win32LoadCursor (IntPtr.Zero, LoadCursorType.IDC_ARROW);
+                               wndClass.hIcon = IntPtr.Zero;
+                               wndClass.hInstance = IntPtr.Zero;
+                               wndClass.lpszClassName = class_name;
+                               wndClass.lpszMenuName = "";
+
+                               bool result = Win32RegisterClass (ref wndClass);
+
+                               if (result == false)
+                                       Win32MessageBox (IntPtr.Zero, "Could not register the window class, win32 error " + Win32GetLastError ().ToString (), "Oops", 0);
+
+                               registered_classes[classStyle] = class_name;
+                       }
+                       
+                       return class_name;
+               }
+
                private static bool RetrieveMessage(ref MSG msg) {
                        MSG     message;
 
@@ -962,6 +1028,14 @@ namespace System.Windows.Forms {
                        }
                }
 
+               internal override int MouseWheelScrollDelta {
+                       get {
+                               int delta = 120;
+                               Win32SystemParametersInfo(SPIAction.SPI_GETWHEELSCROLLLINES, 0, ref delta, 0);
+                               return delta;
+                       }
+               }
+               
                internal override int HorizontalScrollBarHeight {
                        get {
                                return scroll_height;
@@ -1182,12 +1256,14 @@ namespace System.Windows.Forms {
                                ParentHandle = FosterParent;
                        }
 
-                       // Since we fake MDI dont tell Windows that this is a real MDI window
-                       if ((cp.ExStyle & (int) WindowExStyles.WS_EX_MDICHILD) != 0) {
-                               SetMdiStyles (cp);
-                       }
+                       FakeStyles (cp);
+
+                       string class_name = RegisterWindowClass (cp.ClassStyle);
+                       HwndCreating = hwnd;
+
+                       WindowHandle = Win32CreateWindow ((uint)cp.ExStyle, class_name, cp.Caption, (uint)cp.Style, cp.X, cp.Y, cp.Width, cp.Height, ParentHandle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
 
-                       WindowHandle = Win32CreateWindow((uint)cp.ExStyle, cp.ClassName, cp.Caption, (uint)cp.Style, cp.X, cp.Y, cp.Width, cp.Height, ParentHandle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+                       HwndCreating = null;
 
                        if (WindowHandle==IntPtr.Zero) {
                                uint error = Win32GetLastError();
@@ -1267,9 +1343,7 @@ namespace System.Windows.Forms {
 
                internal override void SetWindowStyle(IntPtr handle, CreateParams cp) {
 
-                       if ((cp.ExStyle & (int) WindowExStyles.WS_EX_MDICHILD) != 0) {
-                               SetMdiStyles (cp);
-                       }
+                       FakeStyles (cp);
 
                        Win32SetWindowLong(handle, WindowLong.GWL_STYLE, (uint)cp.Style);
                        Win32SetWindowLong(handle, WindowLong.GWL_EXSTYLE, (uint)cp.ExStyle);
@@ -1470,6 +1544,13 @@ namespace System.Windows.Forms {
                                          SetWindowPosFlags.SWP_DRAWFRAME);
                }
 
+               private IntPtr InternalWndProc (IntPtr hWnd, Msg msg, IntPtr wParam, IntPtr lParam)
+               {
+                       if (HwndCreating != null && HwndCreating.ClientWindow == IntPtr.Zero)
+                               HwndCreating.ClientWindow = hWnd;
+                       return NativeWindow.WndProc (hWnd, msg, wParam, lParam);
+               }
+
                internal override IntPtr DefWndProc(ref Message msg) {
                        msg.Result=Win32DefWindowProc(msg.HWnd, (Msg)msg.Msg, msg.WParam, msg.LParam);
                        return msg.Result;
@@ -1562,7 +1643,7 @@ namespace System.Windows.Forms {
                                }
                        }
 
-                       // We need to fake WM_MOUSE_ENTER/WM_MOUSE_LEAVE
+                       // We need to fake WM_MOUSE_ENTER
                        switch (msg.message) {
                                case Msg.WM_LBUTTONDOWN: {
                                        mouse_state |= MouseButtons.Left;
@@ -1641,7 +1722,6 @@ namespace System.Windows.Forms {
 
                                case Msg.WM_MOUSELEAVE: {
                                        prev_mouse_hwnd = IntPtr.Zero;
-                                       msg.message=Msg.WM_MOUSE_LEAVE;
                                        break;
                                }
 
@@ -1679,7 +1759,7 @@ namespace System.Windows.Forms {
                        return false;
                }
 
-               internal override bool SetTopmost(IntPtr hWnd, IntPtr hWndOwner, bool Enabled) {
+               internal override bool SetTopmost(IntPtr hWnd, bool Enabled) {
                        if (Enabled) {
                                Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_TOPMOST, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
                                return true;
@@ -1688,6 +1768,11 @@ namespace System.Windows.Forms {
                                return true;
                        }
                }
+               
+               internal override bool SetOwner(IntPtr hWnd, IntPtr hWndOwner) {
+                       Win32SetWindowLong(hWnd, WindowLong.GWL_HWNDPARENT, (uint) hWndOwner);
+                       return true;
+               }
 
                internal override bool Text(IntPtr handle, string text) {
                        Win32SetWindowText(handle, text);
@@ -1706,7 +1791,8 @@ namespace System.Windows.Forms {
                internal override bool SetVisible (IntPtr handle, bool visible, bool activate)
                {
                        if (visible) {
-                               if (Control.FromHandle (handle) is Form) {
+                               Control c = Control.FromHandle (handle);
+                               if (c is Form) {
                                        Form f;
 
                                        f = (Form)Control.FromHandle (handle);
@@ -1717,16 +1803,16 @@ namespace System.Windows.Forms {
                                                case FormWindowState.Maximized: flags = WindowPlacementFlags.SW_MAXIMIZE; break;
                                        }
                                        
-                                       if (Hwnd.ObjectFromHandle (handle).no_activate)
-                                               flags |= WindowPlacementFlags.SW_SHOWNOACTIVATE;
+                                       if (!f.ActivateOnShow)
+                                               flags = WindowPlacementFlags.SW_SHOWNOACTIVATE;
                                                
                                        Win32ShowWindow (handle, flags);
                                }
                                else {
-                                       if (Hwnd.ObjectFromHandle (handle).no_activate)
-                                               Win32ShowWindow (handle, WindowPlacementFlags.SW_SHOWNOACTIVATE);
-                                       else
+                                       if (c.ActivateOnShow)
                                                Win32ShowWindow (handle, WindowPlacementFlags.SW_SHOWNORMAL);
+                                       else
+                                               Win32ShowWindow (handle, WindowPlacementFlags.SW_SHOWNOACTIVATE);
                                }
                        }
                        else {
@@ -2006,6 +2092,13 @@ namespace System.Windows.Forms {
                        return;
                }
   
+  #if NET_2_0
+               internal override void ShowBalloonTip(int timeout, string tipTitle, string tipText, ToolTipIcon tipIcon)
+               {
+                       // TODO:
+               }
+#endif
+
                internal override void SendAsyncMethod (AsyncMethodData method)
                {
                        Win32PostMessage(FosterParent, Msg.WM_ASYNC_MESSAGE, IntPtr.Zero, (IntPtr)GCHandle.Alloc (method));
@@ -2036,13 +2129,18 @@ namespace System.Windows.Forms {
                                timer_list.Remove(index);
                        }
                }
-
-               private void SetMdiStyles (CreateParams cp)
+               
+               private void FakeStyles (CreateParams cp)
                {
-                       cp.Style = (int)WindowStyles.WS_CHILD | (int)WindowStyles.WS_CLIPCHILDREN | (int)WindowStyles.WS_CLIPSIBLINGS;
-                       cp.ExStyle = 0;
+                       if (cp.HasWindowManager) {
+                               // Remove all styles but WS_VISIBLE.
+                               cp.WindowStyle &= WindowStyles.WS_VISIBLE;
+                               // Set styles that enables us to use the window manager.
+                               cp.WindowStyle |= WindowStyles.WS_CHILD | WindowStyles.WS_CLIPCHILDREN | WindowStyles.WS_CLIPSIBLINGS;
+                               cp.ExStyle = 0;
+                       }
                }
-       
+               
                internal override void CreateCaret(IntPtr hwnd, int width, int height) {
                        Win32CreateCaret(hwnd, IntPtr.Zero, width, height);
                        caret_visible = false;
@@ -2610,24 +2708,24 @@ namespace System.Windows.Forms {
 
                internal override int KeyboardSpeed {
                        get {
-                               Console.WriteLine ("KeyboardSpeed: need to query Windows");
-
+                               int speed = 0;
+                               Win32SystemParametersInfo(SPIAction.SPI_GETKEYBOARDSPEED, 0, ref speed, 0);
                                //
                                // Return values range from 0 to 31 which map to 2.5 to 30 repetitions per second.
                                //
-                               return 0;
+                               return speed;
                        }
                }
 
                internal override int KeyboardDelay {
                        get {
-                               Console.WriteLine ("KeyboardDelay: need to query Windows");
-
+                               int delay = 1;
+                               Win32SystemParametersInfo(SPIAction.SPI_GETKEYBOARDDELAY, 0, ref delay, 0);
                                //
                                // Return values must range from 0 to 4, 0 meaning 250ms,
                                // and 4 meaning 1000 ms.
                                //
-                               return 1;
+                               return delay;
                        }
                }