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
Hwnd()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 
Dispose()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
ObjectFromWindow(IntPtr window)148 		public static Hwnd ObjectFromWindow(IntPtr window) {
149 			Hwnd rv;
150 			lock (windows) {
151 				rv = (Hwnd)windows[window];
152 			}
153 			return rv;
154 		}
155 
ObjectFromHandle(IntPtr handle)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 
HandleFromObject(Hwnd obj)165 		public static IntPtr HandleFromObject(Hwnd obj) {
166 			return obj.handle;
167 		}
168 
GetObjectFromWindow(IntPtr window)169 		public static Hwnd GetObjectFromWindow(IntPtr window) {
170 			Hwnd rv;
171 			lock (windows) {
172 				rv = (Hwnd)windows[window];
173 			}
174 			return rv;
175 		}
176 
GetHandleFromWindow(IntPtr window)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 
GetBorderWidth(CreateParams cp)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 
GetWindowRectangle(CreateParams cp, Menu menu)255 		public static Rectangle	GetWindowRectangle (CreateParams cp, Menu menu)
256 		{
257 			return GetWindowRectangle (cp, menu, Rectangle.Empty);
258 		}
259 
GetWindowRectangle(CreateParams cp, Menu menu, Rectangle client_rect)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 
GetClientRectangle(int width, int height)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
GetClippingRectangles()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 
GetBorders(CreateParams cp, Menu menu)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 
GetClientRectangle(CreateParams cp, Menu menu, int width, int height)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
AddInvalidArea(int x, int y, int width, int height)763 		public void AddInvalidArea(int x, int y, int width, int height) {
764 			AddInvalidArea(new Rectangle(x, y, width, height));
765 		}
766 
AddInvalidArea(Rectangle rect)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 
ClearInvalidArea()778 		public void ClearInvalidArea() {
779 			invalid_list.Clear();
780 			expose_pending = false;
781 		}
782 
AddNcInvalidArea(int x, int y, int width, int height)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 
AddNcInvalidArea(Rectangle rect)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 
ClearNcInvalidArea()807 		public void ClearNcInvalidArea() {
808 			nc_invalid = Rectangle.Empty;
809 			nc_expose_pending = false;
810 		}
811 
ToString()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 
GetNextStackedFormLocation(CreateParams cp, Hwnd parent_hwnd)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 
InflateSystem.Windows.Forms.Hwnd.Borders876 			public void Inflate (Size size)
877 			{
878 				left += size.Width;
879 				right += size.Width;
880 				top += size.Height;
881 				bottom += size.Height;
882 			}
883 
ToStringSystem.Windows.Forms.Hwnd.Borders884 			public override string ToString ()
885 			{
886 				return string.Format("{{top={0}, bottom={1}, left={2}, right={3}}}", top, bottom, left, right);
887 			}
888 
operator ==System.Windows.Forms.Hwnd.Borders889 			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 
operator !=System.Windows.Forms.Hwnd.Borders894 			public static bool operator != (Borders a, Borders b)
895 			{
896 				return !(a == b);
897 			}
898 
EqualsSystem.Windows.Forms.Hwnd.Borders899 			public override bool Equals (object obj)
900 			{
901 				return base.Equals (obj);
902 			}
903 
GetHashCodeSystem.Windows.Forms.Hwnd.Borders904 			public override int GetHashCode ()
905 			{
906 				return base.GetHashCode ();
907 			}
908 		}
909 	}
910 }
911