2006-05-10 Peter Dennis Bartok <pbartok@novell.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / Control.cs
index 29030e57622cae1588281758f3a4e968225adf7d..a23b86308881afcbfde200ab39205cadbcc11071 100644 (file)
@@ -122,6 +122,7 @@ namespace System.Windows.Forms
 
 #if NET_2_0
                internal bool                   use_compatible_text_rendering;
+               static internal bool            verify_thread_handle;
                private Padding                 padding;
 #endif
 
@@ -163,10 +164,6 @@ namespace System.Windows.Forms
                #region Public Classes
                [ComVisible(true)]
                public class ControlAccessibleObject : AccessibleObject {                       
-                       #region ControlAccessibleObject Local Variables
-                       private Control owner;
-                       #endregion      // ControlAccessibleObject Local Variables
-
                        #region ControlAccessibleObject Constructors
                        public ControlAccessibleObject(Control ownerControl) {
                                this.owner = ownerControl;
@@ -734,7 +731,6 @@ namespace System.Windows.Forms
                private delegate void RemoveDelegate(object c);
 
                protected override void Dispose(bool disposing) {
-                       is_disposed = true;
                        if (dc_mem!=null) {
                                dc_mem.Dispose();
                                dc_mem=null;
@@ -754,6 +750,8 @@ namespace System.Windows.Forms
                                DestroyHandle();
                                controls.Remove(this);
                        }
+                       is_disposed = true;
+                       base.Dispose(disposing);
                }
                #endregion      // Public Constructors
 
@@ -962,6 +960,26 @@ namespace System.Windows.Forms
                // This method exists so controls overriding OnPaintBackground can have default background painting done
                internal virtual void PaintControlBackground (PaintEventArgs pevent)
                {
+                       if (GetStyle(ControlStyles.SupportsTransparentBackColor) && (BackColor.A != 0xff)) {
+                               if (parent != null) {
+                                       PaintEventArgs  parent_pe;
+                                       GraphicsState   state;
+
+                                       parent_pe = new PaintEventArgs(pevent.Graphics, new Rectangle(pevent.ClipRectangle.X + Left, pevent.ClipRectangle.Y + Top, pevent.ClipRectangle.Width, pevent.ClipRectangle.Height));
+
+                                       state = parent_pe.Graphics.Save();
+                                       parent_pe.Graphics.TranslateTransform(-Left, -Top);
+                                       parent.OnPaintBackground(parent_pe);
+                                       parent_pe.Graphics.Restore(state);
+
+                                       state = parent_pe.Graphics.Save();
+                                       parent_pe.Graphics.TranslateTransform(-Left, -Top);
+                                       parent.OnPaint(parent_pe);
+                                       parent_pe.Graphics.Restore(state);
+                                       parent_pe.SetGraphics(null);
+                               }
+                       }
+
                        if (background_image == null) {
                                pevent.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), new Rectangle(pevent.ClipRectangle.X - 1, pevent.ClipRectangle.Y - 1, pevent.ClipRectangle.Width + 2, pevent.ClipRectangle.Height + 2));
                                return;
@@ -1299,10 +1317,12 @@ namespace System.Windows.Forms
                [MonoTODO]
                public static bool CheckForIllegalCrossThreadCalls 
                {
-                       set {
-                       }
                        get {
-                               return false;
+                               return verify_thread_handle;
+                       }
+
+                       set {
+                               verify_thread_handle = value;
                        }
                }
 #endif
@@ -1336,6 +1356,7 @@ namespace System.Windows.Forms
 
                [Localizable(true)]
                [DefaultValue(null)]
+               [MWFCategory("Accessibility")]
                public string AccessibleDescription {
                        get {
                                return AccessibilityObject.description;
@@ -1348,6 +1369,7 @@ namespace System.Windows.Forms
 
                [Localizable(true)]
                [DefaultValue(null)]
+               [MWFCategory("Accessibility")]
                public string AccessibleName {
                        get {
                                return AccessibilityObject.Name;
@@ -1371,6 +1393,7 @@ namespace System.Windows.Forms
                }
 
                [DefaultValue(false)]
+               [MWFCategory("Behavior")]
                public virtual bool AllowDrop {
                        get {
                                return allow_drop;
@@ -1380,14 +1403,17 @@ namespace System.Windows.Forms
                                if (allow_drop == value)
                                        return;
                                allow_drop = value;
-                               UpdateStyles();
-                               XplatUI.SetAllowDrop (Handle, value);
+                               if (IsHandleCreated) {
+                                       UpdateStyles();
+                                       XplatUI.SetAllowDrop (Handle, value);
+                               }
                        }
                }
 
                [Localizable(true)]
                [RefreshProperties(RefreshProperties.Repaint)]
-               [DefaultValue(AnchorStyles.Top | AnchorStyles.Left)]
+               [DefaultValue(AnchorStyles.Top | AnchorStyles.Left)]
+               [MWFCategory("Layout")]
                public virtual AnchorStyles Anchor {
                        get {
                                return anchor_style;
@@ -1419,11 +1445,14 @@ namespace System.Windows.Forms
 #endif // NET_2_0
 
                [DispId(-501)]
+               [MWFCategory("Appearance")]
                public virtual Color BackColor {
                        get {
                                if (background_color.IsEmpty) {
                                        if (parent!=null) {
-                                               return parent.BackColor;
+                                               Color pcolor = parent.BackColor;
+                                               if (pcolor.A == 0xff || GetStyle(ControlStyles.SupportsTransparentBackColor))
+                                                       return pcolor;
                                        }
                                        return DefaultBackColor;
                                }
@@ -1431,6 +1460,10 @@ namespace System.Windows.Forms
                        }
 
                        set {
+                               if (!value.IsEmpty && (value.A != 0xff) && !GetStyle(ControlStyles.SupportsTransparentBackColor)) {
+                                       throw new ArgumentException("Transparent background colors are not supported on this control");
+                               }
+
                                background_color=value;
                                SetChildColor(this);
                                OnBackColorChanged(EventArgs.Empty);
@@ -1440,6 +1473,7 @@ namespace System.Windows.Forms
 
                [Localizable(true)]
                [DefaultValue(null)]
+               [MWFCategory("Appearance")]
                public virtual Image BackgroundImage {
                        get {
                                return background_image;
@@ -1530,6 +1564,16 @@ namespace System.Windows.Forms
                        }
                }
 
+               internal virtual bool InternalCapture {
+                       get {
+                               return Capture;
+                       }
+
+                       set {
+                               Capture = value;
+                       }
+               }
+
                [EditorBrowsable(EditorBrowsableState.Advanced)]
                [Browsable(false)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
@@ -1552,6 +1596,7 @@ namespace System.Windows.Forms
                }
 
                [DefaultValue(true)]
+               [MWFCategory("Focus")]
                public bool CausesValidation {
                        get {
                                return this.causes_validation;
@@ -1624,6 +1669,7 @@ namespace System.Windows.Forms
                }
 
                [DefaultValue(null)]
+               [MWFCategory("Behavior")]
                public virtual ContextMenu ContextMenu {
                        get {
                                return context_menu;
@@ -1655,6 +1701,7 @@ namespace System.Windows.Forms
                }
 
                [AmbientValue(null)]
+               [MWFCategory("Appearance")]
                public virtual Cursor Cursor {
                        get {
                                if (cursor != null) {
@@ -1701,6 +1748,7 @@ namespace System.Windows.Forms
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
                [ParenthesizePropertyName(true)]
                [RefreshProperties(RefreshProperties.All)]
+               [MWFCategory("Data")]
                public ControlBindingsCollection DataBindings {
                        get {
                                if (data_bindings == null)
@@ -1730,6 +1778,7 @@ namespace System.Windows.Forms
                [Localizable(true)]
                [RefreshProperties(RefreshProperties.Repaint)]
                [DefaultValue(DockStyle.None)]
+               [MWFCategory("Layout")]
                public virtual DockStyle Dock {
                        get {
                                return dock_style;
@@ -1752,6 +1801,7 @@ namespace System.Windows.Forms
 
                [DispId(-514)]
                [Localizable(true)]
+               [MWFCategory("Behavior")]
                public bool Enabled {
                        get {
                                if (!is_enabled) {
@@ -1797,6 +1847,7 @@ namespace System.Windows.Forms
                [DispId(-512)]
                [AmbientValue(null)]
                [Localizable(true)]
+               [MWFCategory("Appearance")]
                public virtual Font Font {
                        get {
                                if (font != null) {
@@ -1810,6 +1861,7 @@ namespace System.Windows.Forms
                                return DefaultFont;
                        }
 
+                       [param:MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Font))]
                        set {
                                if (font != null && font.Equals (value)) {
                                        return;
@@ -1822,6 +1874,7 @@ namespace System.Windows.Forms
                }
 
                [DispId(-513)]
+               [MWFCategory("Appearance")]
                public virtual Color ForeColor {
                        get {
                                if (foreground_color.IsEmpty) {
@@ -1847,6 +1900,13 @@ namespace System.Windows.Forms
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
                public IntPtr Handle {                                                  // IWin32Window
                        get {
+#if NET_2_0
+                               if (verify_thread_handle) {
+                                       if (this.InvokeRequired) {
+                                               throw new InvalidOperationException("Cross-thread access of handle detected. Handle access only valid on thread that created the control");
+                                       }
+                               }
+#endif
                                if (!IsHandleCreated) {
                                        CreateHandle();
                                }
@@ -1881,6 +1941,7 @@ namespace System.Windows.Forms
 
                [AmbientValue(ImeMode.Inherit)]
                [Localizable(true)]
+               [MWFCategory("Behavior")]
                public ImeMode ImeMode {
                        get {
                                 if (ime_mode == DefaultImeMode) {
@@ -1962,6 +2023,7 @@ namespace System.Windows.Forms
                }
 
                [Localizable(true)]
+               [MWFCategory("Layout")]
                public Point Location {
                        get {
                                return new Point(bounds.X, bounds.Y);
@@ -2091,6 +2153,7 @@ namespace System.Windows.Forms
 
                [AmbientValue(RightToLeft.Inherit)]
                [Localizable(true)]
+               [MWFCategory("Appearance")]
                public virtual RightToLeft RightToLeft {
                        get {
                                if (right_to_left == RightToLeft.Inherit) {
@@ -2130,6 +2193,7 @@ namespace System.Windows.Forms
                }
 
                [Localizable(true)]
+               [MWFCategory("Layout")]
                public Size Size {
                        get {
                                return new Size(Width, Height);
@@ -2142,6 +2206,7 @@ namespace System.Windows.Forms
 
                [Localizable(true)]
                [MergableProperty(false)]
+               [MWFCategory("Behavior")]
                public int TabIndex {
                        get {
                                if (tab_index != -1) {
@@ -2160,6 +2225,7 @@ namespace System.Windows.Forms
 
                [DispId(-516)]
                [DefaultValue(true)]
+               [MWFCategory("Behavior")]
                public bool TabStop {
                        get {
                                return tab_stop;
@@ -2177,6 +2243,7 @@ namespace System.Windows.Forms
                [Bindable(true)]
                [TypeConverter(typeof(StringConverter))]
                [DefaultValue(null)]
+               [MWFCategory("Data")]
                public object Tag {
                        get {
                                return control_tag;
@@ -2190,6 +2257,7 @@ namespace System.Windows.Forms
                [DispId(-517)]
                [Localizable(true)]
                [BindableAttribute(true)]
+               [MWFCategory("Appearance")]
                public virtual string Text {
                        get {
                                // Our implementation ignores ControlStyles.CacheText - we always cache
@@ -2240,6 +2308,7 @@ namespace System.Windows.Forms
                }
 
                [Localizable(true)]
+               [MWFCategory("Behavior")]
                public bool Visible {
                        get {
                                if (!is_visible) {
@@ -2920,7 +2989,6 @@ namespace System.Windows.Forms
 
                public virtual void Refresh() {                 
                        if (IsHandleCreated == true) {
-
                                Invalidate();
                                XplatUI.UpdateWindow(window.Handle);
 
@@ -2938,9 +3006,8 @@ namespace System.Windows.Forms
                }
 
                [EditorBrowsable(EditorBrowsableState.Never)]
-               [MonoTODO]
                public void ResetBindings() {
-                       // Do something
+                       data_bindings.Clear();
                }
 
                [EditorBrowsable(EditorBrowsableState.Never)]
@@ -3125,8 +3192,10 @@ namespace System.Windows.Forms
                                        }
                                }
 
-                               // Find out where the window manager placed us
                                UpdateStyles();
+                               XplatUI.SetAllowDrop (Handle, allow_drop);
+
+                               // Find out where the window manager placed us
                                if ((CreateParams.Style & (int)WindowStyles.WS_CHILD) != 0) {
                                        XplatUI.SetBorderStyle(window.Handle, (FormBorderStyle)border_style);
                                }
@@ -3530,7 +3599,6 @@ namespace System.Windows.Forms
                        } else {
                                control_style &= ~flag;
                        }
-                       OnStyleChanged(EventArgs.Empty);
                }
 
                protected void SetTopLevel(bool value) {
@@ -3554,6 +3622,10 @@ namespace System.Windows.Forms
 
                protected virtual void SetVisibleCore(bool value) {
                        if (value!=is_visible) {
+                               if (value && !is_created) {
+                                       CreateControl();
+                               }
+
                                is_visible=value;
 
                                if (IsHandleCreated) {
@@ -3565,10 +3637,6 @@ namespace System.Windows.Forms
                                        }
                                }
 
-                               if (is_visible && !is_created) {
-                                       CreateControl();
-                               }
-
                                OnVisibleChanged(EventArgs.Empty);
 
                                if (value == false && parent != null) {
@@ -3659,6 +3727,7 @@ namespace System.Windows.Forms
                        }
 
                        XplatUI.SetWindowStyle(window.Handle, CreateParams);
+                       OnStyleChanged(EventArgs.Empty);
                }
 
                [EditorBrowsable(EditorBrowsableState.Advanced)]
@@ -3705,6 +3774,9 @@ namespace System.Windows.Forms
                                        return;
                                }
 
+                               // Nice description of what should happen when handling WM_PAINT
+                               // can be found here: http://pluralsight.com/wiki/default.aspx/Craig/FlickerFreeControlDrawing.html
+                               // and here http://msdn.microsoft.com/msdnmag/issues/06/03/WindowsFormsPerformance/
                                case Msg.WM_PAINT: {
                                        PaintEventArgs  paint_event;
 
@@ -3723,10 +3795,17 @@ namespace System.Windows.Forms
                                                        dc = paint_event.SetGraphics (DeviceContext);
                                                }
 
-                                       OnPaintBackground(paint_event);
-                                       // Leave out for now, our controls can do Paint += ... as well
-                                       //OnPaintInternal(paint_event);
-                                       OnPaint(paint_event);
+                                       if (!GetStyle(ControlStyles.Opaque)) {
+                                               OnPaintBackground(paint_event);
+                                       }
+
+                                       // Button-derived controls choose to ignore their Opaque style, give them a chance to draw their background anyways
+                                       OnPaintBackgroundInternal(paint_event);
+
+                                       OnPaintInternal(paint_event);
+                                       if (!paint_event.Handled) {
+                                               OnPaint(paint_event);
+                                       }
 
                                        if (ThemeEngine.Current.DoubleBufferingSupported)
                                                if ((control_style & ControlStyles.DoubleBuffer) != 0) {
@@ -3742,6 +3821,8 @@ namespace System.Windows.Forms
                                        
                                case Msg.WM_ERASEBKGND: {
                                        // The DefWndProc will never have to handle this, we always paint the background in managed code
+                                       // In theory this code would look at ControlStyles.AllPaintingInWmPaint and and call OnPaintBackground
+                                       // here but it just makes things more complicated...
                                        m.Result = (IntPtr)1;
                                        return;
                                }
@@ -3757,8 +3838,8 @@ namespace System.Windows.Forms
                                        HandleClick(mouse_clicks, me);
                                        OnMouseUp (me);
 
-                                       if (Capture) {
-                                               Capture = false;
+                                       if (InternalCapture) {
+                                               InternalCapture = false;
                                        }
 
                                        if (mouse_clicks > 1) {
@@ -3771,7 +3852,7 @@ namespace System.Windows.Forms
                                        if (CanSelect && !is_selected) {
                                                Select(this);
                                        }
-                                       Capture = true;
+                                       InternalCapture = true;
                                        OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), 
                                                mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), 
                                                0));
@@ -3780,7 +3861,7 @@ namespace System.Windows.Forms
                                }
 
                                case Msg.WM_LBUTTONDBLCLK: {
-                                       Capture = true;
+                                       InternalCapture = true;
                                        mouse_clicks++;
                                        OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), 
                                                mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), 
@@ -3799,8 +3880,8 @@ namespace System.Windows.Forms
 
                                        HandleClick(mouse_clicks, me);
                                        OnMouseUp (me);
-                                       if (Capture) {
-                                               Capture = false;
+                                       if (InternalCapture) {
+                                               InternalCapture = false;
                                        }
                                        if (mouse_clicks > 1) {
                                                mouse_clicks = 1;
@@ -3809,7 +3890,7 @@ namespace System.Windows.Forms
                                }
                                        
                                case Msg.WM_MBUTTONDOWN: {                                      
-                                       Capture = true;
+                                       InternalCapture = true;
                                        OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), 
                                                mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), 
                                                0));
@@ -3818,7 +3899,7 @@ namespace System.Windows.Forms
                                }
 
                                case Msg.WM_MBUTTONDBLCLK: {
-                                       Capture = true;
+                                       InternalCapture = true;
                                        mouse_clicks++;
                                        OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), 
                                                mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), 
@@ -3827,11 +3908,14 @@ namespace System.Windows.Forms
                                }
 
                                case Msg.WM_RBUTTONUP: {
-                                       MouseEventArgs me;
+                                       MouseEventArgs  me;
+                                       Point           pt;
+
+                                       pt = new Point(LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()));
+                                       pt = PointToScreen(pt);
+
+                                       XplatUI.SendMessage(m.HWnd, Msg.WM_CONTEXTMENU, m.HWnd, (IntPtr)(pt.X + (pt.Y << 16)));
 
-                                       if (context_menu != null) {
-                                               context_menu.Show(this, new Point(LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ())));
-                                       }
                                        me = new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()) | MouseButtons.Right, 
                                                mouse_clicks, 
                                                LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), 
@@ -3840,8 +3924,8 @@ namespace System.Windows.Forms
                                        HandleClick(mouse_clicks, me);
                                        OnMouseUp (me);
 
-                                       if (Capture) {
-                                               Capture = false;
+                                       if (InternalCapture) {
+                                               InternalCapture = false;
                                        }
 
                                        if (mouse_clicks > 1) {
@@ -3851,7 +3935,7 @@ namespace System.Windows.Forms
                                }
                                        
                                case Msg.WM_RBUTTONDOWN: {                                      
-                                       Capture = true;
+                                       InternalCapture = true;
                                        OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), 
                                                mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), 
                                                0));
@@ -3859,7 +3943,7 @@ namespace System.Windows.Forms
                                }
 
                                case Msg.WM_RBUTTONDBLCLK: {
-                                       Capture = true;
+                                       InternalCapture = true;
                                        mouse_clicks++;
                                        OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), 
                                                mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), 
@@ -3867,6 +3951,19 @@ namespace System.Windows.Forms
                                        return;
                                }
 
+                               case Msg.WM_CONTEXTMENU: {
+                                       if (context_menu != null) {
+                                               Point   pt;
+
+                                               pt = new Point(LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()));
+                                               context_menu.Show(this, PointToClient(pt));
+                                               return;
+                                       }
+
+                                       DefWndProc(ref m);
+                                       return;
+                               }
+
                                case Msg.WM_MOUSEWHEEL: {                               
 
                                        OnMouseWheel (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), 
@@ -4246,6 +4343,10 @@ namespace System.Windows.Forms
                        if (Paint!=null) Paint(this, e);
                }
 
+               internal virtual void OnPaintBackgroundInternal(PaintEventArgs e) {
+                       // Override me
+               }
+
                internal virtual void OnPaintInternal(PaintEventArgs e) {
                        // Override me
                }