fixed tests
[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 Menu           menu;
48                 internal TitleStyle     title_style;
49                 internal FormBorderStyle        border_style;
50                 internal bool           border_static;
51                 internal int            x;
52                 internal int            y;
53                 internal int            width;
54                 internal int            height;
55                 internal bool           allow_drop;
56                 internal Hwnd           parent;
57                 internal bool           visible;
58                 internal bool           mapped;
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
84
85                 // locks for some operations (used in XplatUIX11.cs)
86                 internal object configure_lock = new object ();
87                 internal object expose_lock = new object ();
88
89                 #region Constructors and destructors
90                 public Hwnd() {
91                         x = 0;
92                         y = 0;
93                         width = 0;
94                         height = 0;
95                         visible = false;
96                         menu = null;
97                         border_style = FormBorderStyle.None;
98                         client_window = IntPtr.Zero;
99                         whole_window = IntPtr.Zero;
100                         handle = IntPtr.Zero;
101                         parent = null;
102                         invalid_list = new ArrayList();
103                         expose_pending = false;
104                         nc_expose_pending = false;
105                         enabled = true;
106                         reparented = false;
107                         client_rectangle = Rectangle.Empty;
108                         marshal_free_list = new ArrayList(2);
109                         opacity = 0xffffffff;
110                         fixed_size = false;
111                         drawing_stack = new Stack ();
112                 }
113
114                 public void Dispose() {
115                         expose_pending = false;
116                         nc_expose_pending = false;
117                         lock (windows) {
118                                 windows.Remove(client_window);
119                                 windows.Remove(whole_window);
120                         }
121                         client_window = IntPtr.Zero;
122                         whole_window = IntPtr.Zero;
123                         zombie = false;
124                         for (int i = 0; i < marshal_free_list.Count; i++) {
125                                 Marshal.FreeHGlobal((IntPtr)marshal_free_list[i]);
126                         }
127                         marshal_free_list.Clear();
128                 }
129                 #endregion
130
131                 #region Static Methods
132                 public static Hwnd ObjectFromWindow(IntPtr window) {
133                         Hwnd rv;
134                         lock (windows) {
135                                 rv = (Hwnd)windows[window];
136                         }
137                         return rv;
138                 }
139
140                 public static Hwnd ObjectFromHandle(IntPtr handle) {
141                         //return (Hwnd)(((GCHandle)handle).Target);
142                         Hwnd rv;
143                         lock (windows) {
144                                 rv = (Hwnd)windows[handle];
145                         }
146                         return rv;
147                 }
148
149                 public static IntPtr HandleFromObject(Hwnd obj) {
150                         return obj.handle;
151                 }
152
153                 public static Hwnd GetObjectFromWindow(IntPtr window) {
154                         Hwnd rv;
155                         lock (windows) {
156                                 rv = (Hwnd)windows[window];
157                         }
158                         return rv;
159                 }
160
161                 public static IntPtr GetHandleFromWindow(IntPtr window) {
162                         Hwnd    hwnd;
163
164                         lock (windows) {
165                                 hwnd = (Hwnd)windows[window];
166                         }
167                         if (hwnd != null) {
168                                 return hwnd.handle;
169                         } else {
170                                 return IntPtr.Zero;
171                         }
172                 }
173
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)
177                 {
178                         Rectangle       rect;
179
180                         rect = new Rectangle(client_rect.Location, client_rect.Size);
181
182                         if (menu != null) {
183                                 int menu_height = menu.Rect.Height;
184                                 if (menu_height == 0)
185                                         menu_height = ThemeEngine.Current.CalcMenuBarSize(bmp_g, menu, client_rect.Width);
186
187                                 rect.Y -= menu_height;
188                                 rect.Height += menu_height;
189                         }
190
191                         // Adjust rect for borders
192                         Size border_size = new Size (0, 0);
193                         
194                         if (border_static)
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);
202                         
203                         if (border_size.Width != 0) {
204                                 rect.X -= border_size.Width;
205                                 rect.Width += border_size.Width * 2;
206                         }
207
208                         if (border_size.Height != 0) {
209                                 rect.Y -= border_size.Height;
210                                 rect.Height += border_size.Height * 2;
211                         }
212                         
213                         rect.Y -= caption_height;
214                         rect.Height += caption_height;
215
216                         return rect;
217                 }
218
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) {
220                         Rectangle rect;
221
222                         rect = new Rectangle(0, 0, width, height);
223
224                         if (menu != null) {
225                                 int menu_height = menu.Rect.Height;
226                                 rect.Y += menu_height;
227                                 rect.Height -= menu_height;
228                         }
229
230                         Size border_size = new Size (0, 0);
231                         
232                         if (border_static)
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;
238
239                         if (border_size.Width != 0) {
240                                 rect.X += border_size.Width;
241                                 rect.Width -= border_size.Width * 2;
242                         }
243
244                         if (border_size.Height != 0) {
245                                 rect.Y += border_size.Height;
246                                 rect.Height -= border_size.Height * 2;
247                         }
248                         
249                         return rect;
250                 }
251                 #endregion      // Static Methods
252
253                 #region Instance Properties
254                 public FormBorderStyle BorderStyle {
255                         get {
256                                 return border_style;
257                         }
258
259                         set {
260                                 border_style = value;
261                         }
262                 }
263
264                 public Rectangle ClientRect {
265                         get {
266                                 if (client_rectangle == Rectangle.Empty) {
267                                         return DefaultClientRect;
268                                 }
269                                 return client_rectangle;
270                         }
271
272                         set {
273                                 client_rectangle = value;
274                         }
275                 }
276
277                 public IntPtr ClientWindow {
278                         get {
279                                 return client_window;
280                         }
281
282                         set {
283                                 client_window = value;
284                                 handle = value;
285
286                                 zombie = false;
287
288                                 if (client_window != IntPtr.Zero) {
289                                         lock (windows) {
290                                                 if (windows[client_window] == null) {
291                                                         windows[client_window] = this;
292                                                 }
293                                         }
294                                 }
295                         }
296                 }
297
298                 public Region UserClip {
299                         get {
300                                 return user_clip;
301                         }
302
303                         set {
304                                 user_clip = value;
305                         }
306                 }
307
308                 public Rectangle DefaultClientRect {
309                         get {
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);
314                         }
315                 }
316
317                 public bool ExposePending {
318                         get {
319                                 return expose_pending;
320                         }
321                 }
322
323                 public IntPtr Handle {
324                         get {
325                                 if (handle == IntPtr.Zero) {
326                                         throw new ArgumentNullException("Handle", "Handle is not yet assigned, need a ClientWindow");
327                                 }
328                                 return handle;
329                         }
330                 }
331
332                 public int Height {
333                         get {
334                                 return height;
335                         }
336
337                         set {
338                                 height = value;
339                         }
340                 }
341
342                 public Menu Menu {
343                         get {
344                                 return menu;
345                         }
346
347                         set {
348                                 menu = value;
349                         }
350                 }
351
352                 public bool Reparented {
353                         get {
354                                 return reparented;
355                         }
356
357                         set {
358                                 reparented = value;
359                         }
360                 }
361
362                 public uint Opacity {
363                         get {
364                                 return opacity;
365                         }
366
367                         set {
368                                 opacity = value;
369                         }
370                 }
371
372                 public XEventQueue Queue {
373                         get {
374                                 return queue;
375                         }
376
377                         set {
378                                 queue = value;
379                         }
380                 }
381
382                 public bool Enabled {
383                         get {
384                                 if (!enabled) {
385                                         return false;
386                                 }
387
388                                 if (parent != null) {
389                                         return parent.Enabled;
390                                 }
391
392                                 return true;
393                         }
394
395                         set {
396                                 enabled = value;
397                         }
398                 }
399
400                 public IntPtr EnabledHwnd {
401                         get {
402                                 if (Enabled || parent == null) {
403                                         return Handle;
404                                 }
405
406                                 return parent.EnabledHwnd;
407                         }
408                 }
409
410                 public Point MenuOrigin {
411                         get {
412                                 Point   pt;
413                                 Size    border_3D_size = ThemeEngine.Current.Border3DSize;
414
415                                 pt = new Point(0, 0);
416
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) {
421                                         pt.X += 1;
422                                         pt.Y += 1;
423                                 }
424
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;
429                                 }
430
431                                 return pt;
432                         }
433                 }
434
435                 public Rectangle Invalid {
436                         get {
437                                 if (invalid_list.Count == 0)
438                                         return Rectangle.Empty;
439
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]);
443                                 }
444                                 return result;
445                         }
446                 }
447
448                 public Rectangle[] ClipRectangles {
449                         get {
450                                 return (Rectangle[]) invalid_list.ToArray (typeof (Rectangle));
451                         }
452                 }
453
454                 public Rectangle NCInvalid {
455                         get { return nc_invalid; }
456                         set { nc_invalid = value; }
457
458                 }
459
460                 public bool NCExposePending {
461                         get {
462                                 return nc_expose_pending;
463                         }
464                 }
465
466                 public Hwnd Parent {
467                         get {
468                                 return parent;
469                         }
470
471                         set {
472                                 parent = value;
473                         }
474                 }
475
476                 public bool Mapped {
477                         get {
478                                 if (!mapped) {
479                                         return false;
480                                 }
481
482                                 if (parent != null) {
483                                         return parent.Mapped;
484                                 }
485
486                                 return true;
487                         }
488
489                         set {
490                                 mapped = value;
491                         }
492                 }
493
494                 public int CaptionHeight {
495                         get { return caption_height; }
496                         set { caption_height = value; }
497                 }
498
499                 public int ToolCaptionHeight {
500                         get { return tool_caption_height; }
501                         set { tool_caption_height = value; }
502                 }
503
504                 public TitleStyle TitleStyle {
505                         get {
506                                 return title_style;
507                         }
508
509                         set {
510                                 title_style = value;
511                         }
512                 }
513
514                 public object UserData {
515                         get {
516                                 return user_data;
517                         }
518
519                         set {
520                                 user_data = value;
521                         }
522                 }
523
524                 public IntPtr WholeWindow {
525                         get {
526                                 return whole_window;
527                         }
528
529                         set {
530                                 whole_window = value;
531
532                                 zombie = false;
533
534                                 if (whole_window != IntPtr.Zero) {
535                                         lock (windows) {
536                                                 if (windows[whole_window] == null) {
537                                                         windows[whole_window] = this;
538                                                 }
539                                         }
540                                 }
541                         }
542                 }
543
544                 public int Width {
545                         get {
546                                 return width;
547                         }
548
549                         set {
550                                 width = value;
551                         }
552                 }
553
554                 public bool Visible {
555                         get {
556                                 return visible;
557                         }
558
559                         set {
560                                 visible = value;
561                         }
562                 }
563
564                 public int X {
565                         get {
566                                 return x;
567                         }
568
569                         set {
570                                 x = value;
571                         }
572                 }
573
574                 public int Y {
575                         get {
576                                 return y;
577                         }
578
579                         set {
580                                 y = value;
581                         }
582                 }
583
584                 #endregion      // Instance properties
585
586                 #region Methods
587                 public void AddInvalidArea(int x, int y, int width, int height) {
588                         AddInvalidArea(new Rectangle(x, y, width, height));
589                 }
590
591                 public void AddInvalidArea(Rectangle rect) {
592                         ArrayList tmp = new ArrayList ();
593                         foreach (Rectangle r in invalid_list) {
594                                 if (!rect.Contains (r)) {
595                                         tmp.Add (r);
596                                 }
597                         }
598                         tmp.Add (rect);
599                         invalid_list = tmp;
600                 }
601
602                 public void ClearInvalidArea() {
603                         invalid_list.Clear();
604                         expose_pending = false;
605                 }
606
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);
610                                 return;
611                         }
612
613                         int right, bottom;
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);
618
619                         nc_invalid.Width = right - nc_invalid.X;
620                         nc_invalid.Height = bottom - nc_invalid.Y;
621                 }
622
623                 public void AddNcInvalidArea(Rectangle rect) {
624                         if (nc_invalid == Rectangle.Empty) {
625                                 nc_invalid = rect;
626                                 return;
627                         }
628                         nc_invalid = Rectangle.Union (nc_invalid, rect);
629                 }
630
631                 public void ClearNcInvalidArea() {
632                         nc_invalid = Rectangle.Empty;
633                         nc_expose_pending = false;
634                 }
635
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);
638                 }
639
640                 #endregion      // Methods
641         }
642 }