Merge pull request #3591 from directhex/mono_libdir_fallback
[mono.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / Hwnd.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Peter Bartok    (pbartok@novell.com)
24 //
25 //
26
27 // NOT COMPLETE
28
29 using System;
30 using System.Collections;
31 using System.Drawing;
32 using System.Runtime.InteropServices;
33
34 // NOTE: Possible optimization:
35 // Several properties calculate dimensions on the fly; instead; they can 
36 // be stored in a field and only be recalculated when a style is changed (DefaultClientRect, for example)
37
38 namespace System.Windows.Forms {
39         internal class Hwnd : IDisposable {
40                 #region Local Variables
41                 private static Hashtable        windows = new Hashtable(100, 0.5f);
42                 //private const int     menu_height = 14;                       // FIXME - Read this value from somewhere
43                 
44                 private IntPtr          handle;
45                 internal IntPtr         client_window;
46                 internal IntPtr         whole_window;
47                 internal IntPtr         cursor;
48                 internal Menu           menu;
49                 internal TitleStyle     title_style;
50                 internal FormBorderStyle        border_style;
51                 internal bool           border_static;
52                 internal int            x;
53                 internal int            y;
54                 internal int            width;
55                 internal int            height;
56                 internal bool           allow_drop;
57                 internal Hwnd           parent;
58                 internal bool           visible;
59                 internal bool           mapped;
60                 internal uint           opacity;
61                 internal bool           enabled;
62                 internal bool           zero_sized;
63                 internal ArrayList      invalid_list;
64                 internal Rectangle      nc_invalid;
65                 internal bool           expose_pending;
66                 internal bool           nc_expose_pending;
67                 internal bool           configure_pending;
68                 internal bool           resizing_or_moving; // Used by the X11 backend to track form resize/move
69                 internal bool           reparented;
70                 internal Stack          drawing_stack;
71                 internal object         user_data;
72                 internal Rectangle      client_rectangle;
73                 internal ArrayList      marshal_free_list;
74                 internal int            caption_height;
75                 internal int            tool_caption_height;
76                 internal bool           whacky_wm;
77                 internal bool           fixed_size;
78                 internal bool           zombie; /* X11 only flag.  true if the X windows have been destroyed but we haven't been Disposed */
79                 internal bool           topmost; /* X11 only. */
80                 internal Region         user_clip;
81                 internal XEventQueue    queue;
82                 internal WindowExStyles initial_ex_style;
83                 internal WindowStyles   initial_style;
84                 internal FormWindowState cached_window_state = (FormWindowState)(-1);  /* X11 only field */
85                 internal Point          previous_child_startup_location = new Point (int.MinValue, int.MinValue);
86                 static internal Point   previous_main_startup_location = new Point (int.MinValue, int.MinValue);
87                 internal ArrayList children;
88
89                 [ThreadStatic]
90                 private static Bitmap bmp;
91                 [ThreadStatic]
92                 private static Graphics bmp_g;
93                 #endregion      // Local Variables
94
95                 // locks for some operations (used in XplatUIX11.cs)
96                 internal object configure_lock = new object ();
97                 internal object expose_lock = new object ();
98
99                 #region Constructors and destructors
100                 public Hwnd() {
101                         x = 0;
102                         y = 0;
103                         width = 0;
104                         height = 0;
105                         visible = false;
106                         menu = null;
107                         border_style = FormBorderStyle.None;
108                         client_window = IntPtr.Zero;
109                         whole_window = IntPtr.Zero;
110                         cursor = IntPtr.Zero;
111                         handle = IntPtr.Zero;
112                         parent = null;
113                         invalid_list = new ArrayList();
114                         expose_pending = false;
115                         nc_expose_pending = false;
116                         enabled = true;
117                         reparented = false;
118                         client_rectangle = Rectangle.Empty;
119                         marshal_free_list = new ArrayList(2);
120                         opacity = 0xffffffff;
121                         fixed_size = false;
122                         drawing_stack = new Stack ();
123                         children = new ArrayList ();
124                         resizing_or_moving = false;
125                         whacky_wm = false;
126                         topmost = false;
127                 }
128
129                 public void Dispose() {
130                         expose_pending = false;
131                         nc_expose_pending = false;
132                         Parent = null;
133                         lock (windows) {
134                                 windows.Remove(client_window);
135                                 windows.Remove(whole_window);
136                         }
137                         client_window = IntPtr.Zero;
138                         whole_window = IntPtr.Zero;
139                         zombie = false;
140                         for (int i = 0; i < marshal_free_list.Count; i++) {
141                                 Marshal.FreeHGlobal((IntPtr)marshal_free_list[i]);
142                         }
143                         marshal_free_list.Clear();
144                 }
145                 #endregion
146
147                 #region Static Methods
148                 public static Hwnd ObjectFromWindow(IntPtr window) {
149                         Hwnd rv;
150                         lock (windows) {
151                                 rv = (Hwnd)windows[window];
152                         }
153                         return rv;
154                 }
155
156                 public static Hwnd ObjectFromHandle(IntPtr handle) {
157                         //return (Hwnd)(((GCHandle)handle).Target);
158                         Hwnd rv;
159                         lock (windows) {
160                                 rv = (Hwnd)windows[handle];
161                         }
162                         return rv;
163                 }
164
165                 public static IntPtr HandleFromObject(Hwnd obj) {
166                         return obj.handle;
167                 }
168
169                 public static Hwnd GetObjectFromWindow(IntPtr window) {
170                         Hwnd rv;
171                         lock (windows) {
172                                 rv = (Hwnd)windows[window];
173                         }
174                         return rv;
175                 }
176
177                 public static IntPtr GetHandleFromWindow(IntPtr window) {
178                         Hwnd    hwnd;
179
180                         lock (windows) {
181                                 hwnd = (Hwnd)windows[window];
182                         }
183                         if (hwnd != null) {
184                                 return hwnd.handle;
185                         } else {
186                                 return IntPtr.Zero;
187                         }
188                 }
189
190                 public static Borders GetBorderWidth (CreateParams cp)
191                 {
192                         Borders border_size = new Borders ();
193
194                         Size windowborder = ThemeEngine.Current.BorderSize; /*new Size (1, 1);*/ // This is the only one that can be changed from the display properties in windows.
195                         Size border = ThemeEngine.Current.BorderStaticSize; /*new Size (1, 1);*/
196                         Size clientedge = ThemeEngine.Current.Border3DSize; /*new Size (2, 2);*/
197                         Size thickframe = new Size (2 + windowborder.Width, 2 + windowborder.Height);
198                         Size dialogframe = ThemeEngine.Current.BorderSizableSize; /* new Size (3, 3);*/
199                         
200                         if (cp.IsSet (WindowStyles.WS_CAPTION)) {
201                                 border_size.Inflate (dialogframe);
202                         } else if (cp.IsSet (WindowStyles.WS_BORDER)) {
203                                 if (cp.IsSet (WindowExStyles.WS_EX_DLGMODALFRAME)) {
204                                         if (cp.IsSet (WindowStyles.WS_THICKFRAME) && (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE) || cp.IsSet (WindowExStyles.WS_EX_CLIENTEDGE))) {
205                                                 border_size.Inflate (border);
206                                         }
207                                 } else {
208                                         border_size.Inflate (border);
209                                 }
210                         } else if (cp.IsSet (WindowStyles.WS_DLGFRAME)) {
211                                 border_size.Inflate (dialogframe);
212                         }
213
214                         if (cp.IsSet (WindowStyles.WS_THICKFRAME)) {
215                                 if (cp.IsSet (WindowStyles.WS_DLGFRAME)) {
216                                         border_size.Inflate (border);
217                                 } else {
218                                         border_size.Inflate (thickframe);
219                                 }
220                         }
221
222                         bool only_small_border;
223                         Size small_border = Size.Empty;
224
225                         only_small_border = cp.IsSet (WindowStyles.WS_THICKFRAME) || cp.IsSet (WindowStyles.WS_DLGFRAME);
226                         if (only_small_border && cp.IsSet (WindowStyles.WS_THICKFRAME) && !cp.IsSet (WindowStyles.WS_BORDER) && !cp.IsSet (WindowStyles.WS_DLGFRAME)) {
227                                 small_border = border;
228                         }
229
230                         if (cp.IsSet (WindowExStyles.WS_EX_CLIENTEDGE | WindowExStyles.WS_EX_DLGMODALFRAME)) {
231                                 border_size.Inflate (clientedge + (only_small_border ? small_border : dialogframe));
232                         } else if (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE | WindowExStyles.WS_EX_DLGMODALFRAME)) {
233                                 border_size.Inflate (only_small_border ? small_border : dialogframe);
234                         } else if (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE | WindowExStyles.WS_EX_CLIENTEDGE)) {
235                                 border_size.Inflate (border + (only_small_border ? Size.Empty : clientedge));
236                         } else {
237                                 if (cp.IsSet (WindowExStyles.WS_EX_CLIENTEDGE)) {
238                                         border_size.Inflate (clientedge);
239                                 }
240                                 if (cp.IsSet (WindowExStyles.WS_EX_DLGMODALFRAME) && !cp.IsSet (WindowStyles.WS_DLGFRAME)) {
241                                         border_size.Inflate (cp.IsSet (WindowStyles.WS_THICKFRAME) ? border : dialogframe);
242                                 }
243                                 if (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE)) {
244                                         if (cp.IsSet (WindowStyles.WS_THICKFRAME) || cp.IsSet (WindowStyles.WS_DLGFRAME)) {
245                                                 border_size.Inflate (new Size (-border.Width, -border.Height));
246                                         } else {
247                                                 border_size.Inflate (border);
248                                         }
249                                 }
250                         }
251                         
252                         return border_size;
253                 }
254
255                 public static Rectangle GetWindowRectangle (CreateParams cp, Menu menu)
256                 {
257                         return GetWindowRectangle (cp, menu, Rectangle.Empty);
258                 }
259
260                 public static Rectangle GetWindowRectangle (CreateParams cp, Menu menu, Rectangle client_rect)
261                 {
262                         Rectangle rect;
263                         Borders borders;
264
265                         borders = GetBorders (cp, menu);
266
267                         rect = new Rectangle (Point.Empty, client_rect.Size);
268                         rect.Y -= borders.top;
269                         rect.Height += borders.top + borders.bottom;
270                         rect.X -= borders.left;
271                         rect.Width += borders.left + borders.right;
272
273 #if debug
274                         Console.WriteLine ("GetWindowRectangle ({0}, {1}, {2}): {3}", cp, menu != null, client_rect, rect);
275 #endif
276                         return rect;
277                 }
278                 
279                 public Rectangle GetClientRectangle (int width, int height)
280                 {
281                         CreateParams cp = new CreateParams ();
282                         cp.WindowStyle = initial_style;
283                         cp.WindowExStyle = initial_ex_style;
284                         return GetClientRectangle (cp, menu, width, height);
285                 }
286
287                 // This could be greatly optimized by caching the outputs and only updating when something is moved
288                 // in the parent planar space.  To do that we need to track z-order in the parent space as well
289                 public ArrayList GetClippingRectangles ()
290                 {
291                         ArrayList masks = new ArrayList ();
292
293                         if (x < 0) {
294                                 masks.Add (new Rectangle (0, 0, x*-1, Height));
295                                 if (y < 0) {
296                                         masks.Add (new Rectangle (x*-1, 0, Width, y*-1));
297                                 }
298                         } else if (y < 0) {
299                                 masks.Add (new Rectangle (0, 0, Width, y*-1));
300                         }
301
302                         foreach (Hwnd child in children) {
303                                 if (child.visible)
304                                         masks.Add (new Rectangle (child.X, child.Y, child.Width, child.Height));
305                         }
306
307                         if (parent == null) {
308                                 return masks;
309                         }
310
311                         ArrayList siblings = parent.children;
312
313                         foreach (Hwnd sibling in siblings) {
314                                 IntPtr sibling_handle = whole_window;
315
316                                 if (sibling == this)
317                                         continue;
318                                 
319                                 // This entire method should be cached to find all higher views at the time of query
320                                 do {
321                                         sibling_handle = XplatUI.GetPreviousWindow (sibling_handle);
322
323                                         if (sibling_handle == sibling.WholeWindow && sibling.visible) {
324
325                                                 Rectangle intersect = Rectangle.Intersect (new Rectangle (X, Y, Width, Height), new Rectangle (sibling.X, sibling.Y, sibling.Width, sibling.Height));
326                                 
327                                                 if (intersect == Rectangle.Empty)
328                                                         continue;
329                                         
330                                                 intersect.X -= X;
331                                                 intersect.Y -= Y;
332
333                                                 masks.Add (intersect);
334                                         }
335                                 } while (sibling_handle != IntPtr.Zero);
336                         }
337
338                         return masks;
339                 }
340
341                 public static Borders GetBorders (CreateParams cp, Menu menu)
342                 {
343
344                         Borders borders = new Borders ();
345
346                         if (menu != null) {
347                                 int menu_height = menu.Rect.Height;
348                                 if (menu_height == 0)
349                                         menu_height = ThemeEngine.Current.CalcMenuBarSize (GraphicsContext, menu, cp.Width);
350                                 borders.top += menu_height;
351                         }
352                         
353                         if (cp.IsSet (WindowStyles.WS_CAPTION)) {
354                                 int caption_height;
355                                 if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
356                                         caption_height = ThemeEngine.Current.ToolWindowCaptionHeight;
357                                 } else {
358                                         caption_height = ThemeEngine.Current.CaptionHeight;
359                                 }
360                                 borders.top += caption_height;
361                         }
362
363                         Borders border_width = GetBorderWidth (cp);
364
365                         borders.left += border_width.left;
366                         borders.right += border_width.right;
367                         borders.top += border_width.top;
368                         borders.bottom += border_width.bottom;
369                         
370                         return borders;
371                 }
372
373                 public static Rectangle GetClientRectangle(CreateParams cp, Menu menu, int width, int height) {
374                         Rectangle rect;
375                         Borders borders;
376
377                         borders = GetBorders (cp, menu); 
378                         
379                         rect = new Rectangle(0, 0, width, height);
380                         rect.Y += borders.top;
381                         rect.Height -= borders.top + borders.bottom;
382                         rect.X += borders.left;
383                         rect.Width -= borders.left + borders.right;
384                         
385 #if debug
386                         Console.WriteLine ("GetClientRectangle ({0}, {1}, {2}, {3}): {4}", cp, menu != null, width, height, rect);
387 #endif
388                         
389                         return rect;
390                 }
391                 
392                 public static Graphics GraphicsContext {
393                         get {
394                                 if (bmp_g == null) {
395                                         bmp = new Bitmap (1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
396                                         bmp_g = Graphics.FromImage (bmp);
397                                 }
398                         
399                                 return bmp_g;
400                         }
401                 }
402                 #endregion      // Static Methods
403
404                 #region Instance Properties
405                 public FormBorderStyle BorderStyle {
406                         get {
407                                 return border_style;
408                         }
409
410                         set {
411                                 border_style = value;
412                         }
413                 }
414
415                 public Rectangle ClientRect {
416                         get {
417                                 if (client_rectangle == Rectangle.Empty) {
418                                         return DefaultClientRect;
419                                 }
420                                 return client_rectangle;
421                         }
422
423                         set {
424                                 client_rectangle = value;
425                         }
426                 }
427
428                 public IntPtr Cursor {
429                         get {
430                                 return cursor;
431                         }
432
433                         set {
434                                 cursor = value;
435                         }
436                 }
437
438                 public IntPtr ClientWindow {
439                         get {
440                                 return client_window;
441                         }
442
443                         set {
444                                 client_window = value;
445                                 handle = value;
446
447                                 zombie = false;
448
449                                 if (client_window != IntPtr.Zero) {
450                                         lock (windows) {
451                                                 if (windows[client_window] == null) {
452                                                         windows[client_window] = this;
453                                                 }
454                                         }
455                                 }
456                         }
457                 }
458
459                 public Region UserClip {
460                         get {
461                                 return user_clip;
462                         }
463
464                         set {
465                                 user_clip = value;
466                         }
467                 }
468
469                 public Rectangle DefaultClientRect {
470                         get {
471                                 // We pass a Zero for the menu handle so the menu size is
472                                 // not computed this is done via an WM_NCCALC
473                                 CreateParams cp = new CreateParams ();
474                                 Rectangle rect;
475                                 
476                                 cp.WindowStyle = initial_style;
477                                 cp.WindowExStyle = initial_ex_style;
478
479                                 rect = GetClientRectangle (cp, null, width, height);
480
481                                 return rect;
482                         }
483                 }
484
485                 public bool ExposePending {
486                         get {
487                                 return expose_pending;
488                         }
489                 }
490
491                 public IntPtr Handle {
492                         get {
493                                 if (handle == IntPtr.Zero) {
494                                         throw new ArgumentNullException("Handle", "Handle is not yet assigned, need a ClientWindow");
495                                 }
496                                 return handle;
497                         }
498                 }
499
500                 public int Height {
501                         get {
502                                 return height;
503                         }
504
505                         set {
506                                 height = value;
507                         }
508                 }
509
510                 public Menu Menu {
511                         get {
512                                 return menu;
513                         }
514
515                         set {
516                                 menu = value;
517                         }
518                 }
519
520                 public bool Reparented {
521                         get {
522                                 return reparented;
523                         }
524
525                         set {
526                                 reparented = value;
527                         }
528                 }
529
530                 public uint Opacity {
531                         get {
532                                 return opacity;
533                         }
534
535                         set {
536                                 opacity = value;
537                         }
538                 }
539
540                 public XEventQueue Queue {
541                         get {
542                                 return queue;
543                         }
544
545                         set {
546                                 queue = value;
547                         }
548                 }
549
550                 public bool Enabled {
551                         get {
552                                 if (!enabled) {
553                                         return false;
554                                 }
555
556                                 if (parent != null) {
557                                         return parent.Enabled;
558                                 }
559
560                                 return true;
561                         }
562
563                         set {
564                                 enabled = value;
565                         }
566                 }
567
568                 public IntPtr EnabledHwnd {
569                         get {
570                                 if (Enabled || parent == null) {
571                                         return Handle;
572                                 }
573
574                                 return parent.EnabledHwnd;
575                         }
576                 }
577
578                 public Point MenuOrigin {
579                         get {
580                                 Form frm = Control.FromHandle (handle) as Form;
581                                 if (frm != null && frm.window_manager != null)          
582                                         return frm.window_manager.GetMenuOrigin ();
583
584                                 Point   pt;
585                                 Size    border_3D_size = ThemeEngine.Current.Border3DSize;
586
587                                 pt = new Point(0, 0);
588
589                                 if (border_style == FormBorderStyle.Fixed3D) {
590                                         pt.X += border_3D_size.Width;
591                                         pt.Y += border_3D_size.Height;
592                                 } else if (border_style == FormBorderStyle.FixedSingle) {
593                                         pt.X += 1;
594                                         pt.Y += 1;
595                                 }
596
597                                 if (this.title_style == TitleStyle.Normal)  {
598                                         pt.Y += caption_height;
599                                 } else if (this.title_style == TitleStyle.Tool)  {
600                                         pt.Y += tool_caption_height;
601                                 }
602
603                                 return pt;
604                         }
605                 }
606
607                 public Rectangle Invalid {
608                         get {
609                                 if (invalid_list.Count == 0)
610                                         return Rectangle.Empty;
611
612                                 Rectangle result = (Rectangle)invalid_list[0];
613                                 for (int i = 1; i < invalid_list.Count; i ++) {
614                                         result = Rectangle.Union (result, (Rectangle)invalid_list[i]);
615                                 }
616                                 return result;
617                         }
618                 }
619
620                 public Rectangle[] ClipRectangles {
621                         get {
622                                 return (Rectangle[]) invalid_list.ToArray (typeof (Rectangle));
623                         }
624                 }
625
626                 public Rectangle NCInvalid {
627                         get { return nc_invalid; }
628                         set { nc_invalid = value; }
629
630                 }
631
632                 public bool NCExposePending {
633                         get {
634                                 return nc_expose_pending;
635                         }
636                 }
637
638                 public Hwnd Parent {
639                         get {
640                                 return parent;
641                         }
642
643                         set {
644                                 if (parent != null)
645                                         parent.children.Remove (this);
646                                 parent = value;
647                                 if (parent != null)
648                                         parent.children.Add (this);
649                         }
650                 }
651
652                 public bool Mapped {
653                         get {
654                                 if (!mapped) {
655                                         return false;
656                                 }
657
658                                 if (parent != null) {
659                                         return parent.Mapped;
660                                 }
661
662                                 return true;
663                         }
664
665                         set {
666                                 mapped = value;
667                         }
668                 }
669
670                 public int CaptionHeight {
671                         get { return caption_height; }
672                         set { caption_height = value; }
673                 }
674
675                 public int ToolCaptionHeight {
676                         get { return tool_caption_height; }
677                         set { tool_caption_height = value; }
678                 }
679
680                 public TitleStyle TitleStyle {
681                         get {
682                                 return title_style;
683                         }
684
685                         set {
686                                 title_style = value;
687                         }
688                 }
689
690                 public object UserData {
691                         get {
692                                 return user_data;
693                         }
694
695                         set {
696                                 user_data = value;
697                         }
698                 }
699
700                 public IntPtr WholeWindow {
701                         get {
702                                 return whole_window;
703                         }
704
705                         set {
706                                 whole_window = value;
707
708                                 zombie = false;
709
710                                 if (whole_window != IntPtr.Zero) {
711                                         lock (windows) {
712                                                 if (windows[whole_window] == null) {
713                                                         windows[whole_window] = this;
714                                                 }
715                                         }
716                                 }
717                         }
718                 }
719
720                 public int Width {
721                         get {
722                                 return width;
723                         }
724
725                         set {
726                                 width = value;
727                         }
728                 }
729
730                 public bool Visible {
731                         get {
732                                 return visible;
733                         }
734
735                         set {
736                                 visible = value;
737                         }
738                 }
739
740                 public int X {
741                         get {
742                                 return x;
743                         }
744
745                         set {
746                                 x = value;
747                         }
748                 }
749
750                 public int Y {
751                         get {
752                                 return y;
753                         }
754
755                         set {
756                                 y = value;
757                         }
758                 }
759
760                 #endregion      // Instance properties
761
762                 #region Methods
763                 public void AddInvalidArea(int x, int y, int width, int height) {
764                         AddInvalidArea(new Rectangle(x, y, width, height));
765                 }
766
767                 public void AddInvalidArea(Rectangle rect) {
768                         ArrayList tmp = new ArrayList ();
769                         foreach (Rectangle r in invalid_list) {
770                                 if (!rect.Contains (r)) {
771                                         tmp.Add (r);
772                                 }
773                         }
774                         tmp.Add (rect);
775                         invalid_list = tmp;
776                 }
777
778                 public void ClearInvalidArea() {
779                         invalid_list.Clear();
780                         expose_pending = false;
781                 }
782
783                 public void AddNcInvalidArea(int x, int y, int width, int height) {
784                         if (nc_invalid == Rectangle.Empty) {
785                                 nc_invalid = new Rectangle (x, y, width, height);
786                                 return;
787                         }
788
789                         int right, bottom;
790                         right = Math.Max (nc_invalid.Right, x + width);
791                         bottom = Math.Max (nc_invalid.Bottom, y + height);
792                         nc_invalid.X = Math.Min (nc_invalid.X, x);
793                         nc_invalid.Y = Math.Min (nc_invalid.Y, y);
794
795                         nc_invalid.Width = right - nc_invalid.X;
796                         nc_invalid.Height = bottom - nc_invalid.Y;
797                 }
798
799                 public void AddNcInvalidArea(Rectangle rect) {
800                         if (nc_invalid == Rectangle.Empty) {
801                                 nc_invalid = rect;
802                                 return;
803                         }
804                         nc_invalid = Rectangle.Union (nc_invalid, rect);
805                 }
806
807                 public void ClearNcInvalidArea() {
808                         nc_invalid = Rectangle.Empty;
809                         nc_expose_pending = false;
810                 }
811
812                 public override string ToString() {
813                         return String.Format("Hwnd, Mapped:{3} ClientWindow:0x{0:X}, WholeWindow:0x{1:X}, Zombie={4}, Parent:[{2:X}]", client_window.ToInt32(), whole_window.ToInt32(), parent != null ? parent.ToString() : "<null>", Mapped, zombie);
814                 }
815
816                 public static Point GetNextStackedFormLocation  (CreateParams cp, Hwnd parent_hwnd)
817                 {
818                         if (cp.control == null)
819                                 return Point.Empty;
820                 
821                         int X = cp.X;
822                         int Y = cp.Y;
823                         Point previous, next;
824                         Rectangle within;
825
826                         if (parent_hwnd != null) {
827                                 Control parent = cp.control.Parent;
828                                 previous = parent_hwnd.previous_child_startup_location;
829                                 if (parent_hwnd.client_rectangle == Rectangle.Empty && parent != null) {
830                                         within = parent.ClientRectangle;
831                                 } else {
832                                         within = parent_hwnd.client_rectangle;
833                                 }
834                         } else {
835                                 previous = Hwnd.previous_main_startup_location;
836                                 within = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
837                         }
838
839                         if (previous.X == int.MinValue || previous.Y == int.MinValue) {
840                                 next = Point.Empty;
841                         } else {
842                                 next = new Point (previous.X + 22, previous.Y + 22);
843                         }
844
845                         if (!within.Contains (next.X * 3, next.Y * 3)) {
846                                 next = Point.Empty;
847                         }
848
849                         if (next == Point.Empty && cp.Parent == IntPtr.Zero) {
850                                 next = new Point (22, 22);
851                         }
852
853                         if (parent_hwnd != null) {
854                                 parent_hwnd.previous_child_startup_location = next;
855                         } else {
856                                 Hwnd.previous_main_startup_location = next;
857                         }
858
859                         if (X == int.MinValue && Y == int.MinValue) {
860                                 X = next.X;
861                                 Y = next.Y;
862                         }
863                         
864                         return new Point (X, Y);
865                 }
866
867                 #endregion      // Methods
868                 
869                 internal struct Borders
870                 {
871                         public int top;
872                         public int bottom;
873                         public int left;
874                         public int right;
875
876                         public void Inflate (Size size)
877                         {
878                                 left += size.Width;
879                                 right += size.Width;
880                                 top += size.Height;
881                                 bottom += size.Height;
882                         }
883
884                         public override string ToString ()
885                         {
886                                 return string.Format("{{top={0}, bottom={1}, left={2}, right={3}}}", top, bottom, left, right);
887                         }
888                         
889                         public static bool operator == (Borders a, Borders b)
890                         {
891                                 return (a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom);
892                         }
893                         
894                         public static bool operator != (Borders a, Borders b)
895                         {
896                                 return !(a == b);
897                         }
898
899                         public override bool Equals (object obj)
900                         {
901                                 return base.Equals (obj);
902                         }
903
904                         public override int GetHashCode ()
905                         {
906                                 return base.GetHashCode ();
907                         }
908                 }
909         }
910 }