2007-01-02 Chris Toshok <toshok@ximian.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / Hwnd.cs
index c9f7acd395f1abf18a39c055b6ccdc4b799c6fbc..3a03e010af2bca3f14755a6126e2e4ae965d5ab1 100644 (file)
@@ -17,7 +17,7 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
 //
 // Authors:
 //     Peter Bartok    (pbartok@novell.com)
@@ -40,13 +40,11 @@ namespace System.Windows.Forms {
                #region Local Variables
                private static Hashtable        windows = new Hashtable(100, 0.5f);
                //private const int     menu_height = 14;                       // FIXME - Read this value from somewhere
-               private const int       caption_height = 0;                     // FIXME - Read this value from somewhere
-               private const int       tool_caption_height = 0;                // FIXME - Read this value from somewhere
-
+               
                private IntPtr          handle;
                internal IntPtr         client_window;
                internal IntPtr         whole_window;
-               internal IntPtr         menu_handle;
+               internal Menu           menu;
                internal TitleStyle     title_style;
                internal FormBorderStyle        border_style;
                internal int            x;
@@ -56,17 +54,37 @@ namespace System.Windows.Forms {
                internal bool           allow_drop;
                internal Hwnd           parent;
                internal bool           visible;
+               internal bool           mapped;
+               internal uint           opacity;
+               internal bool           enabled;
                internal bool           zero_sized;
-               internal Rectangle      invalid;
+               internal ArrayList      invalid_list;
+               internal Rectangle      nc_invalid;
                internal bool           expose_pending;
                internal bool           nc_expose_pending;
                internal bool           configure_pending;
-               internal Graphics       client_dc;
+               internal bool           reparented;
+               internal Stack          drawing_stack;
                internal object         user_data;
                internal Rectangle      client_rectangle;
                internal ArrayList      marshal_free_list;
+               internal int            caption_height;
+               internal int            tool_caption_height;
+               internal bool           whacky_wm;
+               internal bool           fixed_size;
+               internal bool           zombie; /* X11 only flag.  true if the X windows have been destroyed but we haven't been Disposed */
+               internal Region         user_clip;
+               internal static Bitmap  bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+               internal static Graphics bmp_g = Graphics.FromImage (bmp);
+               internal XEventQueue    queue;
+               internal bool           no_activate;    // For Win32, popup windows will not steal focus
+               internal WindowExStyles initial_ex_style;
                #endregion      // Local Variables
 
+               // locks for some operations (used in XplatUIX11.cs)
+               internal object configure_lock = new object ();
+               internal object expose_lock = new object ();
+
                #region Constructors and destructors
                public Hwnd() {
                        x = 0;
@@ -74,22 +92,34 @@ namespace System.Windows.Forms {
                        width = 0;
                        height = 0;
                        visible = false;
-                       menu_handle = IntPtr.Zero;
+                       menu = null;
                        border_style = FormBorderStyle.None;
                        client_window = IntPtr.Zero;
                        whole_window = IntPtr.Zero;
                        handle = IntPtr.Zero;
                        parent = null;
-                       invalid = Rectangle.Empty;
+                       invalid_list = new ArrayList();
                        expose_pending = false;
                        nc_expose_pending = false;
+                       enabled = true;
+                       reparented = false;
                        client_rectangle = Rectangle.Empty;
                        marshal_free_list = new ArrayList(2);
+                       opacity = 0xffffffff;
+                       fixed_size = false;
+                       drawing_stack = new Stack ();
                }
 
                public void Dispose() {
-                       windows[client_window] = null;
-                       windows[whole_window] = null;
+                       expose_pending = false;
+                       nc_expose_pending = false;
+                       lock (windows) {
+                               windows.Remove(client_window);
+                               windows.Remove(whole_window);
+                       }
+                       client_window = IntPtr.Zero;
+                       whole_window = IntPtr.Zero;
+                       zombie = false;
                        for (int i = 0; i < marshal_free_list.Count; i++) {
                                Marshal.FreeHGlobal((IntPtr)marshal_free_list[i]);
                        }
@@ -98,17 +128,21 @@ namespace System.Windows.Forms {
                #endregion
 
                #region Static Methods
-               public void SetObjectWindow(Hwnd obj, IntPtr window) {
-                       windows[window] = obj;
-               }
-
                public static Hwnd ObjectFromWindow(IntPtr window) {
-                       return (Hwnd)windows[window];
+                       Hwnd rv;
+                       lock (windows) {
+                               rv = (Hwnd)windows[window];
+                       }
+                       return rv;
                }
 
                public static Hwnd ObjectFromHandle(IntPtr handle) {
                        //return (Hwnd)(((GCHandle)handle).Target);
-                       return (Hwnd)windows[handle];
+                       Hwnd rv;
+                       lock (windows) {
+                               rv = (Hwnd)windows[handle];
+                       }
+                       return rv;
                }
 
                public static IntPtr HandleFromObject(Hwnd obj) {
@@ -116,13 +150,19 @@ namespace System.Windows.Forms {
                }
 
                public static Hwnd GetObjectFromWindow(IntPtr window) {
-                       return (Hwnd)windows[window];
+                       Hwnd rv;
+                       lock (windows) {
+                               rv = (Hwnd)windows[window];
+                       }
+                       return rv;
                }
 
                public static IntPtr GetHandleFromWindow(IntPtr window) {
                        Hwnd    hwnd;
 
-                       hwnd = (Hwnd)windows[window];
+                       lock (windows) {
+                               hwnd = (Hwnd)windows[window];
+                       }
                        if (hwnd != null) {
                                return hwnd.handle;
                        } else {
@@ -130,70 +170,58 @@ namespace System.Windows.Forms {
                        }
                }
 
-               public static Rectangle GetWindowRectangle(FormBorderStyle border_style, IntPtr menu_handle, TitleStyle title_style, Rectangle client_rect) {
+               public static Rectangle GetWindowRectangle(FormBorderStyle border_style,
+                               Menu menu, TitleStyle title_style, int caption_height,
+                               int tool_caption_height, Rectangle client_rect)
+               {
                        Rectangle       rect;
 
                        rect = new Rectangle(client_rect.Location, client_rect.Size);
 
-                       if (menu_handle != IntPtr.Zero) {
-                               MenuAPI.MENU menu = MenuAPI.GetMenuFromID (menu_handle);
-                               if (menu != null) {
-                                       int menu_height = menu.Height;
-                                       rect.Y -= menu_height;
-                                       rect.Height += menu_height;
-                               } else
-                                       Console.WriteLine("Hwnd.GetWindowRectangle: No MENU for menu_handle = {0}", menu_handle);
-                       }
-
-                       switch(border_style) {
-                               case FormBorderStyle.Fixed3D: {
-                                       rect.X -= 2;
-                                       rect.Y -= 2;
-                                       rect.Width += 4;
-                                       rect.Height += 4;
-                                       break;
-                               }
+                       if (menu != null) {
+                               int menu_height = menu.Rect.Height;
+                               if (menu_height == 0)
+                                       menu_height = ThemeEngine.Current.CalcMenuBarSize(bmp_g, menu, client_rect.Width);
 
-                               case FormBorderStyle.FixedSingle: {
-                                       rect.X -= 1;
-                                       rect.Y -= 1;
-                                       rect.Width += 2;
-                                       rect.Height += 2;
-                                       break;
-                               }
+                               rect.Y -= menu_height;
+                               rect.Height += menu_height;
                        }
 
-                       if (title_style == TitleStyle.Normal) {
-                               rect.Y -= caption_height;
-                               rect.Height += caption_height;
-                       } else if (title_style == TitleStyle.Tool) {
-                               rect.Y -= tool_caption_height;
-                               rect.Height += tool_caption_height;
+                       if (border_style == FormBorderStyle.Fixed3D) {
+                               Size border_3D_size = ThemeEngine.Current.Border3DSize;
+
+                               rect.X -= border_3D_size.Width;
+                               rect.Y -= border_3D_size.Height;
+                               rect.Width += border_3D_size.Width * 2;
+                               rect.Height += border_3D_size.Height * 2;
+                       } else if (border_style == FormBorderStyle.FixedSingle) {
+                               rect.X -= 1;
+                               rect.Y -= 1;
+                               rect.Width += 2;
+                               rect.Height += 2;
                        }
 
                        return rect;
                }
 
-               public static Rectangle GetClientRectangle(FormBorderStyle border_style, IntPtr menu_handle, TitleStyle title_style, int width, int height) {
+               public static Rectangle GetClientRectangle(FormBorderStyle border_style, Menu menu, TitleStyle title_style, int caption_height, int tool_caption_height, int width, int height) {
                        Rectangle rect;
 
                        rect = new Rectangle(0, 0, width, height);
 
-                       if (menu_handle != IntPtr.Zero) {
-                               MenuAPI.MENU menu = MenuAPI.GetMenuFromID (menu_handle);
-                               if (menu != null) {
-                                       int menu_height = menu.Height;
-                                       rect.Y += menu_height;
-                                       rect.Height -= menu_height;
-                               } else
-                                       Console.WriteLine("Hwnd.GetClientRectangle: No MENU for menu_handle = {0}", menu_handle);
+                       if (menu != null) {
+                               int menu_height = menu.Rect.Height;
+                               rect.Y += menu_height;
+                               rect.Height -= menu_height;
                        }
 
                        if (border_style == FormBorderStyle.Fixed3D) {
-                               rect.X += 2;
-                               rect.Y += 2;
-                               rect.Width -= 4;
-                               rect.Height -= 4;
+                               Size border_3D_size = ThemeEngine.Current.Border3DSize;
+
+                               rect.X += border_3D_size.Width;
+                               rect.Y += border_3D_size.Height;
+                               rect.Width -= border_3D_size.Width * 2;
+                               rect.Height -= border_3D_size.Height * 2;
                        } else if (border_style == FormBorderStyle.FixedSingle) {
                                rect.X += 1;
                                rect.Y += 1;
@@ -201,14 +229,6 @@ namespace System.Windows.Forms {
                                rect.Height -= 2;
                        }
 
-                       if (title_style == TitleStyle.Normal)  {
-                               rect.Y += caption_height;
-                               rect.Height -= caption_height;
-                       } else if (title_style == TitleStyle.Normal)  {
-                               rect.Y += tool_caption_height;
-                               rect.Height -= tool_caption_height;
-                       }
-
                        return rect;
                }
                #endregion      // Static Methods
@@ -224,16 +244,6 @@ namespace System.Windows.Forms {
                        }
                }
 
-               public Graphics ClientDC {
-                       get {
-                               return client_dc;
-                       }
-
-                       set {
-                               client_dc = value;
-                       }
-               }
-
                public Rectangle ClientRect {
                        get {
                                if (client_rectangle == Rectangle.Empty) {
@@ -256,39 +266,34 @@ namespace System.Windows.Forms {
                                client_window = value;
                                handle = value;
 
-                               if (windows[client_window] == null) {
-                                       windows[client_window] = this;
+                               zombie = false;
+
+                               if (client_window != IntPtr.Zero) {
+                                       lock (windows) {
+                                               if (windows[client_window] == null) {
+                                                       windows[client_window] = this;
+                                               }
+                                       }
                                }
                        }
                }
 
-               public Rectangle DefaultClientRect {
+               public Region UserClip {
                        get {
-                               Rectangle rect;
-
-                               rect = new Rectangle(0, 0, width, height);
-
-                               if (border_style == FormBorderStyle.Fixed3D) {
-                                       rect.X += 2;
-                                       rect.Y += 2;
-                                       rect.Width -= 4;
-                                       rect.Height -= 4;
-                               } else if (border_style == FormBorderStyle.FixedSingle) {
-                                       rect.X += 1;
-                                       rect.Y += 1;
-                                       rect.Width -= 2;
-                                       rect.Height -= 2;
-                               }
+                               return user_clip;
+                       }
 
-                               if (this.title_style == TitleStyle.Normal)  {
-                                       rect.Y += caption_height;
-                                       rect.Height -= caption_height;
-                               } else if (this.title_style == TitleStyle.Normal)  {
-                                       rect.Y += tool_caption_height;
-                                       rect.Height -= tool_caption_height;
-                               }
+                       set {
+                               user_clip = value;
+                       }
+               }
 
-                               return rect;
+               public Rectangle DefaultClientRect {
+                       get {
+                               // We pass a Zero for the menu handle so the menu size is
+                               // not computed this is done via an WM_NCCALC
+                               return GetClientRectangle (border_style, null, title_style,
+                                               caption_height, tool_caption_height, width, height);
                        }
                }
 
@@ -296,10 +301,6 @@ namespace System.Windows.Forms {
                        get {
                                return expose_pending;
                        }
-
-                       set {
-                               expose_pending = value;
-                       }
                }
 
                public IntPtr Handle {
@@ -321,25 +322,84 @@ namespace System.Windows.Forms {
                        }
                }
 
-               public IntPtr MenuHandle {
+               public Menu Menu {
+                       get {
+                               return menu;
+                       }
+
+                       set {
+                               menu = value;
+                       }
+               }
+
+               public bool Reparented {
+                       get {
+                               return reparented;
+                       }
+
+                       set {
+                               reparented = value;
+                       }
+               }
+
+               public uint Opacity {
+                       get {
+                               return opacity;
+                       }
+
+                       set {
+                               opacity = value;
+                       }
+               }
+
+               public XEventQueue Queue {
                        get {
-                               return menu_handle;
+                               return queue;
                        }
 
                        set {
-                               menu_handle = value;
+                               queue = value;
+                       }
+               }
+
+               public bool Enabled {
+                       get {
+                               if (!enabled) {
+                                       return false;
+                               }
+
+                               if (parent != null) {
+                                       return parent.Enabled;
+                               }
+
+                               return true;
+                       }
+
+                       set {
+                               enabled = value;
+                       }
+               }
+
+               public IntPtr EnabledHwnd {
+                       get {
+                               if (Enabled || parent == null) {
+                                       return Handle;
+                               }
+
+                               return parent.EnabledHwnd;
                        }
                }
 
                public Point MenuOrigin {
                        get {
                                Point   pt;
+                               Size    border_3D_size = ThemeEngine.Current.Border3DSize;
 
                                pt = new Point(0, 0);
 
                                if (border_style == FormBorderStyle.Fixed3D) {
-                                       pt.X += 2;
-                                       pt.Y += 2;
+                                       pt.X += border_3D_size.Width;
+                                       pt.Y += border_3D_size.Height;
                                } else if (border_style == FormBorderStyle.FixedSingle) {
                                        pt.X += 1;
                                        pt.Y += 1;
@@ -354,24 +414,36 @@ namespace System.Windows.Forms {
                                return pt;
                        }
                }
+
                public Rectangle Invalid {
                        get {
-                               return invalid;
-                       }
+                               if (invalid_list.Count == 0)
+                                       return Rectangle.Empty;
 
-                       set {
-                               invalid = value;
+                               Rectangle result = (Rectangle)invalid_list[0];
+                               for (int i = 1; i < invalid_list.Count; i ++) {
+                                       result = Rectangle.Union (result, (Rectangle)invalid_list[i]);
+                               }
+                               return result;
                        }
                }
 
+               public Rectangle[] ClipRectangles {
+                       get {
+                               return (Rectangle[]) invalid_list.ToArray (typeof (Rectangle));
+                       }
+               }
+
+               public Rectangle NCInvalid {
+                       get { return nc_invalid; }
+                       set { nc_invalid = value; }
+
+               }
+
                public bool NCExposePending {
                        get {
                                return nc_expose_pending;
                        }
-
-                       set {
-                               nc_expose_pending = value;
-                       }
                }
 
                public Hwnd Parent {
@@ -384,6 +456,34 @@ namespace System.Windows.Forms {
                        }
                }
 
+               public bool Mapped {
+                       get {
+                               if (!mapped) {
+                                       return false;
+                               }
+
+                               if (parent != null) {
+                                       return parent.Mapped;
+                               }
+
+                               return true;
+                       }
+
+                       set {
+                               mapped = value;
+                       }
+               }
+
+               public int CaptionHeight {
+                       get { return caption_height; }
+                       set { caption_height = value; }
+               }
+
+               public int ToolCaptionHeight {
+                       get { return tool_caption_height; }
+                       set { tool_caption_height = value; }
+               }
+
                public TitleStyle TitleStyle {
                        get {
                                return title_style;
@@ -412,8 +512,14 @@ namespace System.Windows.Forms {
                        set {
                                whole_window = value;
 
-                               if (windows[whole_window] == null) {
-                                       windows[whole_window] = this;
+                               zombie = false;
+
+                               if (whole_window != IntPtr.Zero) {
+                                       lock (windows) {
+                                               if (windows[whole_window] == null) {
+                                                       windows[whole_window] = this;
+                                               }
+                                       }
                                }
                        }
                }
@@ -457,37 +563,63 @@ namespace System.Windows.Forms {
                                y = value;
                        }
                }
+
                #endregion      // Instance properties
 
                #region Methods
                public void AddInvalidArea(int x, int y, int width, int height) {
-                       if (invalid == Rectangle.Empty) {
-                               invalid = new Rectangle (x, y, width, height);
+                       AddInvalidArea(new Rectangle(x, y, width, height));
+               }
+
+               public void AddInvalidArea(Rectangle rect) {
+                       ArrayList tmp = new ArrayList ();
+                       foreach (Rectangle r in invalid_list) {
+                               if (!rect.Contains (r)) {
+                                       tmp.Add (r);
+                               }
+                       }
+                       tmp.Add (rect);
+                       invalid_list = tmp;
+               }
+
+               public void ClearInvalidArea() {
+                       invalid_list.Clear();
+                       expose_pending = false;
+               }
+
+               public void AddNcInvalidArea(int x, int y, int width, int height) {
+                       if (nc_invalid == Rectangle.Empty) {
+                               nc_invalid = new Rectangle (x, y, width, height);
                                return;
                        }
 
                        int right, bottom;
-                       right = Math.Max (invalid.Right, x + width);
-                       bottom = Math.Max (invalid.Bottom, y + height);
-                       invalid.X = Math.Min (invalid.X, x);
-                       invalid.Y = Math.Min (invalid.Y, y);
+                       right = Math.Max (nc_invalid.Right, x + width);
+                       bottom = Math.Max (nc_invalid.Bottom, y + height);
+                       nc_invalid.X = Math.Min (nc_invalid.X, x);
+                       nc_invalid.Y = Math.Min (nc_invalid.Y, y);
 
-                       invalid.Width = right - invalid.X;
-                       invalid.Height = bottom - invalid.Y;
+                       nc_invalid.Width = right - nc_invalid.X;
+                       nc_invalid.Height = bottom - nc_invalid.Y;
                }
 
-               public void AddInvalidArea(Rectangle rect) {
-                       if (invalid == Rectangle.Empty) {
-                               invalid = rect;
+               public void AddNcInvalidArea(Rectangle rect) {
+                       if (nc_invalid == Rectangle.Empty) {
+                               nc_invalid = rect;
                                return;
                        }
-                       invalid = Rectangle.Union (invalid, rect);
+                       nc_invalid = Rectangle.Union (nc_invalid, rect);
                }
 
-               public void ClearInvalidArea() {
-                       invalid = Rectangle.Empty;
-                       expose_pending = false;
+               public void ClearNcInvalidArea() {
+                       nc_invalid = Rectangle.Empty;
+                       nc_expose_pending = false;
+               }
+
+               public override string ToString() {
+                       return String.Format("Hwnd, Mapped:{3} ClientWindow:0x{0:X}, WholeWindow:0x{1:X}, Parent:[{2:X}]", client_window.ToInt32(), whole_window.ToInt32(), parent != null ? parent.ToString() : "<null>", Mapped);
                }
+
                #endregion      // Methods
        }
 }