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