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:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
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.
20 // Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
23 // Peter Bartok (pbartok@novell.com)
30 using System.Collections;
32 using System.Runtime.InteropServices;
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)
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
44 private IntPtr handle;
45 internal IntPtr client_window;
46 internal IntPtr whole_window;
48 internal TitleStyle title_style;
49 internal FormBorderStyle border_style;
50 internal bool border_static;
55 internal bool allow_drop;
57 internal bool visible;
59 internal uint opacity;
60 internal bool enabled;
61 internal bool zero_sized;
62 internal ArrayList invalid_list;
63 internal Rectangle nc_invalid;
64 internal bool expose_pending;
65 internal bool nc_expose_pending;
66 internal bool configure_pending;
67 internal bool reparented;
68 internal Stack drawing_stack;
69 internal object user_data;
70 internal Rectangle client_rectangle;
71 internal ArrayList marshal_free_list;
72 internal int caption_height;
73 internal int tool_caption_height;
74 internal bool whacky_wm;
75 internal bool fixed_size;
76 internal bool zombie; /* X11 only flag. true if the X windows have been destroyed but we haven't been Disposed */
77 internal Region user_clip;
78 internal static Bitmap bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
79 internal static Graphics bmp_g = Graphics.FromImage (bmp);
80 internal XEventQueue queue;
81 internal bool no_activate; // For Win32, popup windows will not steal focus
82 internal WindowExStyles initial_ex_style;
83 #endregion // Local Variables
85 // locks for some operations (used in XplatUIX11.cs)
86 internal object configure_lock = new object ();
87 internal object expose_lock = new object ();
89 #region Constructors and destructors
97 border_style = FormBorderStyle.None;
98 client_window = IntPtr.Zero;
99 whole_window = IntPtr.Zero;
100 handle = IntPtr.Zero;
102 invalid_list = new ArrayList();
103 expose_pending = false;
104 nc_expose_pending = false;
107 client_rectangle = Rectangle.Empty;
108 marshal_free_list = new ArrayList(2);
109 opacity = 0xffffffff;
111 drawing_stack = new Stack ();
114 public void Dispose() {
115 expose_pending = false;
116 nc_expose_pending = false;
118 windows.Remove(client_window);
119 windows.Remove(whole_window);
121 client_window = IntPtr.Zero;
122 whole_window = IntPtr.Zero;
124 for (int i = 0; i < marshal_free_list.Count; i++) {
125 Marshal.FreeHGlobal((IntPtr)marshal_free_list[i]);
127 marshal_free_list.Clear();
131 #region Static Methods
132 public static Hwnd ObjectFromWindow(IntPtr window) {
135 rv = (Hwnd)windows[window];
140 public static Hwnd ObjectFromHandle(IntPtr handle) {
141 //return (Hwnd)(((GCHandle)handle).Target);
144 rv = (Hwnd)windows[handle];
149 public static IntPtr HandleFromObject(Hwnd obj) {
153 public static Hwnd GetObjectFromWindow(IntPtr window) {
156 rv = (Hwnd)windows[window];
161 public static IntPtr GetHandleFromWindow(IntPtr window) {
165 hwnd = (Hwnd)windows[window];
174 public static Rectangle GetWindowRectangle(FormBorderStyle border_style, bool border_static,
175 Menu menu, TitleStyle title_style, int caption_height,
176 int tool_caption_height, Rectangle client_rect)
180 rect = new Rectangle(client_rect.Location, client_rect.Size);
183 int menu_height = menu.Rect.Height;
184 if (menu_height == 0)
185 menu_height = ThemeEngine.Current.CalcMenuBarSize(bmp_g, menu, client_rect.Width);
187 rect.Y -= menu_height;
188 rect.Height += menu_height;
191 // Adjust rect for borders
192 Size border_size = new Size (0, 0);
195 border_size = ThemeEngine.Current.BorderStaticSize;
196 else if (border_style == FormBorderStyle.FixedSingle)
197 border_size = ThemeEngine.Current.BorderSize;
198 else if (border_style == FormBorderStyle.Fixed3D)
199 border_size = ThemeEngine.Current.Border3DSize;
200 else if (border_style == (FormBorderStyle) 0xFFFF)
201 border_size = new Size(4, 4);
203 if (border_size.Width != 0) {
204 rect.X -= border_size.Width;
205 rect.Width += border_size.Width * 2;
208 if (border_size.Height != 0) {
209 rect.Y -= border_size.Height;
210 rect.Height += border_size.Height * 2;
213 rect.Y -= caption_height;
214 rect.Height += caption_height;
219 public static Rectangle GetClientRectangle(FormBorderStyle border_style, bool border_static, Menu menu, TitleStyle title_style, int caption_height, int tool_caption_height, int width, int height) {
222 rect = new Rectangle(0, 0, width, height);
225 int menu_height = menu.Rect.Height;
226 rect.Y += menu_height;
227 rect.Height -= menu_height;
230 Size border_size = new Size (0, 0);
233 border_size = ThemeEngine.Current.BorderStaticSize;
234 else if (border_style == FormBorderStyle.FixedSingle)
235 border_size = ThemeEngine.Current.BorderSize;
236 else if (border_style == FormBorderStyle.Fixed3D)
237 border_size = ThemeEngine.Current.Border3DSize;
239 if (border_size.Width != 0) {
240 rect.X += border_size.Width;
241 rect.Width -= border_size.Width * 2;
244 if (border_size.Height != 0) {
245 rect.Y += border_size.Height;
246 rect.Height -= border_size.Height * 2;
251 #endregion // Static Methods
253 #region Instance Properties
254 public FormBorderStyle BorderStyle {
260 border_style = value;
264 public Rectangle ClientRect {
266 if (client_rectangle == Rectangle.Empty) {
267 return DefaultClientRect;
269 return client_rectangle;
273 client_rectangle = value;
277 public IntPtr ClientWindow {
279 return client_window;
283 client_window = value;
288 if (client_window != IntPtr.Zero) {
290 if (windows[client_window] == null) {
291 windows[client_window] = this;
298 public Region UserClip {
308 public Rectangle DefaultClientRect {
310 // We pass a Zero for the menu handle so the menu size is
311 // not computed this is done via an WM_NCCALC
312 return GetClientRectangle (border_style, border_static, null, title_style,
313 caption_height, tool_caption_height, width, height);
317 public bool ExposePending {
319 return expose_pending;
323 public IntPtr Handle {
325 if (handle == IntPtr.Zero) {
326 throw new ArgumentNullException("Handle", "Handle is not yet assigned, need a ClientWindow");
352 public bool Reparented {
362 public uint Opacity {
372 public XEventQueue Queue {
382 public bool Enabled {
388 if (parent != null) {
389 return parent.Enabled;
400 public IntPtr EnabledHwnd {
402 if (Enabled || parent == null) {
406 return parent.EnabledHwnd;
410 public Point MenuOrigin {
413 Size border_3D_size = ThemeEngine.Current.Border3DSize;
415 pt = new Point(0, 0);
417 if (border_style == FormBorderStyle.Fixed3D) {
418 pt.X += border_3D_size.Width;
419 pt.Y += border_3D_size.Height;
420 } else if (border_style == FormBorderStyle.FixedSingle) {
425 if (this.title_style == TitleStyle.Normal) {
426 pt.Y += caption_height;
427 } else if (this.title_style == TitleStyle.Normal) {
428 pt.Y += tool_caption_height;
435 public Rectangle Invalid {
437 if (invalid_list.Count == 0)
438 return Rectangle.Empty;
440 Rectangle result = (Rectangle)invalid_list[0];
441 for (int i = 1; i < invalid_list.Count; i ++) {
442 result = Rectangle.Union (result, (Rectangle)invalid_list[i]);
448 public Rectangle[] ClipRectangles {
450 return (Rectangle[]) invalid_list.ToArray (typeof (Rectangle));
454 public Rectangle NCInvalid {
455 get { return nc_invalid; }
456 set { nc_invalid = value; }
460 public bool NCExposePending {
462 return nc_expose_pending;
482 if (parent != null) {
483 return parent.Mapped;
494 public int CaptionHeight {
495 get { return caption_height; }
496 set { caption_height = value; }
499 public int ToolCaptionHeight {
500 get { return tool_caption_height; }
501 set { tool_caption_height = value; }
504 public TitleStyle TitleStyle {
514 public object UserData {
524 public IntPtr WholeWindow {
530 whole_window = value;
534 if (whole_window != IntPtr.Zero) {
536 if (windows[whole_window] == null) {
537 windows[whole_window] = this;
554 public bool Visible {
584 #endregion // Instance properties
587 public void AddInvalidArea(int x, int y, int width, int height) {
588 AddInvalidArea(new Rectangle(x, y, width, height));
591 public void AddInvalidArea(Rectangle rect) {
592 ArrayList tmp = new ArrayList ();
593 foreach (Rectangle r in invalid_list) {
594 if (!rect.Contains (r)) {
602 public void ClearInvalidArea() {
603 invalid_list.Clear();
604 expose_pending = false;
607 public void AddNcInvalidArea(int x, int y, int width, int height) {
608 if (nc_invalid == Rectangle.Empty) {
609 nc_invalid = new Rectangle (x, y, width, height);
614 right = Math.Max (nc_invalid.Right, x + width);
615 bottom = Math.Max (nc_invalid.Bottom, y + height);
616 nc_invalid.X = Math.Min (nc_invalid.X, x);
617 nc_invalid.Y = Math.Min (nc_invalid.Y, y);
619 nc_invalid.Width = right - nc_invalid.X;
620 nc_invalid.Height = bottom - nc_invalid.Y;
623 public void AddNcInvalidArea(Rectangle rect) {
624 if (nc_invalid == Rectangle.Empty) {
628 nc_invalid = Rectangle.Union (nc_invalid, rect);
631 public void ClearNcInvalidArea() {
632 nc_invalid = Rectangle.Empty;
633 nc_expose_pending = false;
636 public override string ToString() {
637 return String.Format("Hwnd, Mapped:{3} ClientWindow:0x{0:X}, WholeWindow:0x{1:X}, Parent:[{2:X}]", client_window.ToInt32(), whole_window.ToInt32(), parent != null ? parent.ToString() : "<null>", Mapped);
640 #endregion // Methods