2009-03-18 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / XplatUICarbon.cs
index 1685c194cc18b912c4e12e0600ef96eeca6ab0a8..fb44a43f850f9a4cad1cb4f82b9f3105e54a6a33 100644 (file)
@@ -70,7 +70,7 @@ namespace System.Windows.Forms {
                
                // Carbon Specific
                internal static GrabStruct Grab;
-               private static Carbon.Caret Caret;
+               internal static Carbon.Caret Caret;
                private static Carbon.Dnd Dnd;
                private static Hashtable WindowMapping;
                private static Hashtable HandleMapping;
@@ -87,6 +87,7 @@ namespace System.Windows.Forms {
 
                // Timers
                private ArrayList TimerList;
+               private static bool in_doevents;
                
                static readonly object instancelock = new object ();
                static readonly object queuelock = new object ();
@@ -100,6 +101,7 @@ namespace System.Windows.Forms {
 
                        RefCount = 0;
                        TimerList = new ArrayList ();
+                       in_doevents = false;
                        MessageQueue = new Queue ();
                        
                        Initialize ();
@@ -486,8 +488,17 @@ namespace System.Windows.Forms {
                                for (int i = 0; i < TimerList.Count; i++) {
                                        Timer timer = (Timer) TimerList [i];
                                        if (timer.Enabled && timer.Expires <= now) {
-                                               timer.FireTick ();
-                                               timer.Update (now);
+                                               // Timer ticks:
+                                               //  - Before MainForm.OnLoad if DoEvents () is called.
+                                               //  - After MainForm.OnLoad if not.
+                                               //
+                                               if (in_doevents ||
+                                                   (Application.MWFThread.Current.Context != null && 
+                                                    Application.MWFThread.Current.Context.MainForm != null && 
+                                                    Application.MWFThread.Current.Context.MainForm.IsLoaded)) {
+                                                       timer.FireTick ();
+                                                       timer.Update (now);
+                                               }
                                        }
                                }
                        }
@@ -721,7 +732,7 @@ namespace System.Windows.Forms {
 
                        if (client) {
                                hwnd.AddInvalidArea(x, y, width, height);
-                               if (!hwnd.expose_pending) {
+                               if (!hwnd.expose_pending && hwnd.visible) {
                                        MSG msg = new MSG ();
                                        msg.message = Msg.WM_PAINT;
                                        msg.hwnd = hwnd.Handle;
@@ -730,7 +741,7 @@ namespace System.Windows.Forms {
                                }
                        } else {
                                hwnd.AddNcInvalidArea (x, y, width, height);
-                               if (!hwnd.nc_expose_pending) {
+                               if (!hwnd.nc_expose_pending && hwnd.visible) {
                                        MSG msg = new MSG ();
                                        Region rgn = new Region (hwnd.Invalid);
                                        IntPtr hrgn = rgn.GetHrgn (null); // Graphics object isn't needed
@@ -740,6 +751,7 @@ namespace System.Windows.Forms {
                                        msg.hwnd = hwnd.Handle;
                                        MessageQueue.Enqueue (msg);
                                        hwnd.nc_expose_pending = true;
+
                                }
                        }
                }
@@ -770,7 +782,11 @@ namespace System.Windows.Forms {
                }
 
                internal override void Activate(IntPtr handle) {
+                       if (ActiveWindow != IntPtr.Zero) {
+                               ActivateWindow (HIViewGetWindow (ActiveWindow), false);
+                       }
                        ActivateWindow (HIViewGetWindow (handle), true);
+                       ActiveWindow = handle;
                }
 
                internal override void AudibleAlert() {
@@ -1021,7 +1037,7 @@ namespace System.Windows.Forms {
                        SendMessage (hwnd.Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */);
                        SendParentNotify (hwnd.Handle, Msg.WM_CREATE, int.MaxValue, int.MaxValue);
 
-                       if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE) || StyleSet (cp.Style, WindowStyles.WS_POPUP)) {
+                       if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) {
                                if (WindowHandle != IntPtr.Zero) {
                                        if (Control.FromHandle(hwnd.Handle) is Form) {
                                                Form f = Control.FromHandle(hwnd.Handle) as Form;
@@ -1029,11 +1045,8 @@ namespace System.Windows.Forms {
                                                        SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
                                                }
                                        }
-                                       IntPtr active = GetActive ();
                                        ShowWindow (WindowHandle);
                                        WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
-                                       if (active != IntPtr.Zero)
-                                               Activate (active);
                                }
                                HIViewSetVisible (WholeWindow, true);
                                HIViewSetVisible (ClientWindow, true);
@@ -1043,6 +1056,12 @@ namespace System.Windows.Forms {
                                }
                        }
 
+                       if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE)) {
+                               SetWindowState(hwnd.Handle, FormWindowState.Minimized);
+                       } else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE)) {
+                               SetWindowState(hwnd.Handle, FormWindowState.Maximized);
+                       }
+
                        return hwnd.Handle;
                }
 
@@ -1064,77 +1083,16 @@ namespace System.Windows.Forms {
                        return CreateWindow(create_params);
                }
 
-               [MonoTODO]
-               internal override Bitmap DefineStdCursorBitmap (StdCursor id)
-               {
-                       throw new NotImplementedException ();
+               internal override Bitmap DefineStdCursorBitmap (StdCursor id) {
+                       return Carbon.Cursor.DefineStdCursorBitmap (id);
                }
-               [MonoTODO]
-               internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) {
-                       return IntPtr.Zero;
+
+               internal override IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) {
+                       return Carbon.Cursor.DefineCursor (bitmap, mask, cursor_pixel, mask_pixel, xHotSpot, yHotSpot);
                }
                
-               internal override IntPtr DefineStdCursor(StdCursor id) {
-                       switch (id) {
-                               case StdCursor.AppStarting:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeSpinningCursor;
-                               case StdCursor.Arrow:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.Cross:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeCrossCursor;
-                               case StdCursor.Default:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.Hand:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeOpenHandCursor;
-                               case StdCursor.Help:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.HSplit:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeResizeLeftRightCursor;
-                               case StdCursor.IBeam:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeIBeamCursor;
-                               case StdCursor.No:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeNotAllowedCursor;
-                               case StdCursor.NoMove2D:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeNotAllowedCursor;
-                               case StdCursor.NoMoveHoriz:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeNotAllowedCursor;
-                               case StdCursor.NoMoveVert:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeNotAllowedCursor;
-                               case StdCursor.PanEast:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeResizeRightCursor;
-                               case StdCursor.PanNE:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.PanNorth:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.PanNW:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.PanSE:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.PanSouth:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.PanSW:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.PanWest:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeResizeLeftCursor;
-                               case StdCursor.SizeAll:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeResizeLeftRightCursor;
-                               case StdCursor.SizeNESW:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.SizeNS:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.SizeNWSE:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.SizeWE:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.UpArrow:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.VSplit:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                               case StdCursor.WaitCursor:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeSpinningCursor;
-                               default:
-                                       return (IntPtr)Carbon.ThemeCursor.kThemeArrowCursor;
-                       }
+               internal override IntPtr DefineStdCursor (StdCursor id) {
+                       return Carbon.Cursor.DefineStdCursor (id);
                }
                
                internal override IntPtr DefWndProc(ref Message msg) {
@@ -1174,6 +1132,57 @@ namespace System.Windows.Forms {
                                        }
                                        break;
                                }
+                               case Msg.WM_SETCURSOR: {
+                                       // Pass to parent window first
+                                       while ((hwnd.parent != null) && (msg.Result == IntPtr.Zero)) {
+                                               hwnd = hwnd.parent;
+                                               msg.Result = NativeWindow.WndProc(hwnd.Handle, Msg.WM_SETCURSOR, msg.HWnd, msg.LParam);
+                                       }
+
+                                       if (msg.Result == IntPtr.Zero) {
+                                               IntPtr handle;
+
+                                               switch((HitTest)(msg.LParam.ToInt32() & 0xffff)) {
+                                                       case HitTest.HTBOTTOM:          handle = Cursors.SizeNS.handle; break;
+                                                       case HitTest.HTBORDER:          handle = Cursors.SizeNS.handle; break;
+                                                       case HitTest.HTBOTTOMLEFT:      handle = Cursors.SizeNESW.handle; break;
+                                                       case HitTest.HTBOTTOMRIGHT:     handle = Cursors.SizeNWSE.handle; break;
+                                                       case HitTest.HTERROR:           if ((msg.LParam.ToInt32() >> 16) == (int)Msg.WM_LBUTTONDOWN) {
+                                                                                               //FIXME: AudibleAlert();
+                                                                                       }
+                                                                                       handle = Cursors.Default.handle;
+                                                                                       break;
+
+                                                       case HitTest.HTHELP:            handle = Cursors.Help.handle; break;
+                                                       case HitTest.HTLEFT:            handle = Cursors.SizeWE.handle; break;
+                                                       case HitTest.HTRIGHT:           handle = Cursors.SizeWE.handle; break;
+                                                       case HitTest.HTTOP:             handle = Cursors.SizeNS.handle; break;
+                                                       case HitTest.HTTOPLEFT:         handle = Cursors.SizeNWSE.handle; break;
+                                                       case HitTest.HTTOPRIGHT:        handle = Cursors.SizeNESW.handle; break;
+
+                                                       #if SameAsDefault
+                                                       case HitTest.HTGROWBOX:
+                                                       case HitTest.HTSIZE:
+                                                       case HitTest.HTZOOM:
+                                                       case HitTest.HTVSCROLL:
+                                                       case HitTest.HTSYSMENU:
+                                                       case HitTest.HTREDUCE:
+                                                       case HitTest.HTNOWHERE:
+                                                       case HitTest.HTMAXBUTTON:
+                                                       case HitTest.HTMINBUTTON:
+                                                       case HitTest.HTMENU:
+                                                       case HitTest.HSCROLL:
+                                                       case HitTest.HTBOTTOM:
+                                                       case HitTest.HTCAPTION:
+                                                       case HitTest.HTCLIENT:
+                                                       case HitTest.HTCLOSE:
+                                                       #endif
+                                                       default: handle = Cursors.Default.handle; break;
+                                               }
+                                               SetCursor(msg.HWnd, handle);
+                                       }
+                                       return (IntPtr)1;
+                               }
                        }
                        return IntPtr.Zero;
                }
@@ -1226,8 +1235,10 @@ namespace System.Windows.Forms {
                                CFRelease (hwnd.client_window);
                        */
 
-                       if (WindowMapping [hwnd.Handle] != null) 
+                       if (WindowMapping [hwnd.Handle] != null) 
                                DisposeWindow ((IntPtr)(WindowMapping [hwnd.Handle]));
+                               WindowMapping.Remove (hwnd.Handle);
+                       }
                }
 
                internal override IntPtr DispatchMessage(ref MSG msg) {
@@ -1235,6 +1246,15 @@ namespace System.Windows.Forms {
                }
                
                internal override void DoEvents() {
+                        MSG     msg = new MSG ();
+
+                       in_doevents = true;
+                       while (PeekMessage (null, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
+                                TranslateMessage (ref msg);
+                                DispatchMessage (ref msg);
+                        }
+                       in_doevents = false;
+
                }
 
                internal override void EnableWindow(IntPtr handle, bool Enable) {
@@ -1249,11 +1269,7 @@ namespace System.Windows.Forms {
                }
                
                internal override IntPtr GetActive() {
-                       foreach (DictionaryEntry entry in WindowMapping)
-                               if (IsWindowActive ((IntPtr)(entry.Value)))
-                                       return (IntPtr)(entry.Key);
-
-                       return IntPtr.Zero;
+                       return ActiveWindow;
                }
 
                internal override Region GetClipRegion(IntPtr hwnd) {
@@ -1334,7 +1350,7 @@ namespace System.Windows.Forms {
                                        if (Idle != null) 
                                                Idle (this, EventArgs.Empty);
                                        else if (TimerList.Count == 0) {
-                                               ReceiveNextEvent (0, IntPtr.Zero, Convert.ToDouble ("0." + Timer.Minimum), true, ref evtRef);
+                                               ReceiveNextEvent (0, IntPtr.Zero, 0.15, true, ref evtRef);
                                                if (evtRef != IntPtr.Zero && target != IntPtr.Zero) {
                                                        SendEventToEventTarget (evtRef, target);
                                                        ReleaseEvent (evtRef);
@@ -1562,7 +1578,33 @@ namespace System.Windows.Forms {
                }
                
                internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) {
-                       return true;
+                       IntPtr evtRef = IntPtr.Zero;
+                       IntPtr target = GetEventDispatcherTarget();
+                       CheckTimers (DateTime.UtcNow);
+                       ReceiveNextEvent (0, IntPtr.Zero, 0, true, ref evtRef);
+                       if (evtRef != IntPtr.Zero && target != IntPtr.Zero) {
+                               SendEventToEventTarget (evtRef, target);
+                               ReleaseEvent (evtRef);
+                       }
+                       
+                       lock (queuelock) {
+                               if (MessageQueue.Count <= 0) {
+                                       return false;
+                               } else {
+                                       object queueobj;
+                                       if (flags == (uint)PeekMessageFlags.PM_REMOVE)
+                                               queueobj = MessageQueue.Dequeue ();
+                                       else
+                                               queueobj = MessageQueue.Peek ();
+
+                                       if (queueobj is GCHandle) {
+                                               XplatUIDriverSupport.ExecuteClientMessage((GCHandle)queueobj);
+                                               return false;
+                                       }
+                                       msg = (MSG)queueobj;
+                                       return true;
+                               }
+                       }
                }
 
                internal override bool PostMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) {
@@ -1620,20 +1662,20 @@ namespace System.Windows.Forms {
                }
 
                internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool clear) {
-                       Carbon.HIRect scroll_rect = new Carbon.HIRect ();
-                       scroll_rect.origin.x = area.X;
-                       scroll_rect.origin.y = area.Y;
-                       scroll_rect.size.width = area.Width;
-                       scroll_rect.size.height = area.Height;
-                       HIViewScrollRect (handle, ref scroll_rect, (float)XAmount, (float)YAmount);
+                       /*
+                        * This used to use a HIViewScrollRect but this causes issues with the fact that we dont coalesce
+                        * updates properly with our short-circuiting of the window manager.  For now we'll do a less
+                        * efficient invalidation of the entire handle which appears to fix the problem
+                        * see bug #381084
+                        */
+                       Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
+                       Invalidate (handle, new Rectangle (0, 0, hwnd.Width, hwnd.Height), false);
                }
                
                
-               internal override void ScrollWindow(IntPtr hwnd, int XAmount, int YAmount, bool clear) {
-                       Carbon.HIRect scroll_rect = new Carbon.HIRect ();
-                       
-                       HIViewGetBounds (hwnd, ref scroll_rect);
-                       HIViewScrollRect (hwnd, ref scroll_rect, (float)XAmount, (float)YAmount);
+               internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool clear) {
+                       Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
+                       Invalidate (handle, new Rectangle (0, 0, hwnd.Width, hwnd.Height), false);
                }
                
                [MonoTODO]
@@ -1653,13 +1695,13 @@ namespace System.Windows.Forms {
 
 
                internal override void SetCaretPos (IntPtr hwnd, int x, int y) {
-                       if (Caret.Hwnd == hwnd) {
+                       if (hwnd != IntPtr.Zero && hwnd == Caret.Hwnd) {
+                               Caret.X = x;
+                               Caret.Y = y;
                                ClientToScreen (hwnd, ref x, ref y);
                                SizeWindow (new Rectangle (x, y, Caret.Width, Caret.Height), CaretWindow);
                                Caret.Timer.Stop ();
                                HideCaret ();
-                               Caret.X = x;
-                               Caret.Y = y;
                                if (Caret.Visible == 1) {
                                        ShowCaret ();
                                        Caret.Timer.Start ();
@@ -1674,10 +1716,7 @@ namespace System.Windows.Forms {
                internal override void SetCursor(IntPtr window, IntPtr cursor) {
                        Hwnd hwnd = Hwnd.ObjectFromHandle (window);
 
-                       if (hwnd.Handle == window)
-                               hwnd.ClientCursor = cursor;
-                       else
-                               hwnd.WholeCursor = cursor;
+                       hwnd.Cursor = cursor;
                }
                
                internal override void SetCursorPos(IntPtr handle, int x, int y) {
@@ -1795,6 +1834,7 @@ namespace System.Windows.Forms {
                        HIViewSetVisible (hwnd.client_window, visible);
 
                        hwnd.visible = visible;
+                       hwnd.Mapped = true;
                        return true;
                }
                
@@ -1872,14 +1912,20 @@ namespace System.Windows.Forms {
                                SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
 
                                Control ctrl = Control.FromHandle (handle);
-                               Size TranslatedSize = TranslateWindowSizeToQuartzWindowSize (ctrl.GetCreateParams (), new Size (width, height));
+                               CreateParams cp = ctrl.GetCreateParams ();
+                               Size TranslatedSize = TranslateWindowSizeToQuartzWindowSize (cp, new Size (width, height));
                                Carbon.Rect rect = new Carbon.Rect ();
 
                                if (WindowMapping [hwnd.Handle] != null) {
-                                       SetRect (ref rect, (short)x, (short)(y+MenuBarHeight), (short)(x+TranslatedSize.Width), (short)(y+MenuBarHeight+TranslatedSize.Height));
+                                       if (StyleSet (cp.Style, WindowStyles.WS_POPUP)) {
+                                               SetRect (ref rect, (short)x, (short)y, (short)(x+TranslatedSize.Width), (short)(y+TranslatedSize.Height));
+                                       } else {
+                                               SetRect (ref rect, (short)x, (short)(y+MenuBarHeight), (short)(x+TranslatedSize.Width), (short)(y+MenuBarHeight+TranslatedSize.Height));
+                                       }
                                        SetWindowBounds ((IntPtr) WindowMapping [hwnd.Handle], 33, ref rect);
                                        Carbon.HIRect frame_rect = new Carbon.HIRect (0, 0, TranslatedSize.Width, TranslatedSize.Height);
                                        HIViewSetFrame (hwnd.whole_window, ref frame_rect);
+                                       SetCaretPos (Caret.Hwnd, Caret.X, Caret.Y);
                                } else {
                                        Carbon.HIRect frame_rect = new Carbon.HIRect (x, y, TranslatedSize.Width, TranslatedSize.Height);
                                        HIViewSetFrame (hwnd.whole_window, ref frame_rect);
@@ -1968,7 +2014,7 @@ namespace System.Windows.Forms {
                                return true;
                        } else if (!Bottom) {
                                Hwnd after_hwnd = Hwnd.ObjectFromHandle (after_handle);
-                               HIViewSetZOrder (hwnd.whole_window, 2, after_hwnd.whole_window);
+                               HIViewSetZOrder (hwnd.whole_window, 2, (after_handle == IntPtr.Zero ? IntPtr.Zero : after_hwnd.whole_window));
                        } else {
                                HIViewSetZOrder (hwnd.whole_window, 1, IntPtr.Zero);
                                return true;
@@ -2156,7 +2202,6 @@ namespace System.Windows.Forms {
                                return false;
                        }
                }
-               internal override Size MinimizedWindowSize { get{ throw new NotImplementedException(); } }
                internal override Size MinimizedWindowSpacingSize { get{ throw new NotImplementedException(); } }
 
                internal override Size MinimumWindowSize {
@@ -2165,8 +2210,6 @@ namespace System.Windows.Forms {
                        }
                }
 
-               internal override Size MinWindowTrackSize { get{ throw new NotImplementedException(); } }
-               
                internal override Keys ModifierKeys {
                        get {
                                return KeyboardHandler.ModifierKeys;
@@ -2177,6 +2220,12 @@ namespace System.Windows.Forms {
                internal override bool MouseButtonsSwapped { get{ throw new NotImplementedException(); } }
                internal override bool MouseWheelPresent { get{ throw new NotImplementedException(); } }
 
+               internal override MouseButtons MouseButtons {
+                       get {
+                               return MouseState;
+                       }
+               }
+
                internal override Rectangle VirtualScreen {
                        get {
                                return WorkingArea;