* Form.cs: remove unused "active_form" static field.
[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 int            x;
51                 internal int            y;
52                 internal int            width;
53                 internal int            height;
54                 internal bool           allow_drop;
55                 internal Hwnd           parent;
56                 internal bool           visible;
57                 internal bool           mapped;
58                 internal uint           opacity;
59                 internal bool           enabled;
60                 internal bool           zero_sized;
61                 internal ArrayList      invalid_list;
62                 internal Rectangle      nc_invalid;
63                 internal bool           expose_pending;
64                 internal bool           nc_expose_pending;
65                 internal bool           configure_pending;
66                 internal bool           reparented;
67                 internal Graphics       client_dc;
68                 internal Graphics       non_client_dc;
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 Region         user_clip;
77                 internal static Bitmap  bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
78                 internal XEventQueue    queue;
79                 #endregion      // Local Variables
80
81                 #region Constructors and destructors
82                 public Hwnd() {
83                         x = 0;
84                         y = 0;
85                         width = 0;
86                         height = 0;
87                         visible = false;
88                         menu = null;
89                         border_style = FormBorderStyle.None;
90                         client_window = IntPtr.Zero;
91                         whole_window = IntPtr.Zero;
92                         handle = IntPtr.Zero;
93                         parent = null;
94                         invalid_list = new ArrayList();
95                         expose_pending = false;
96                         nc_expose_pending = false;
97                         enabled = true;
98                         reparented = false;
99                         client_rectangle = Rectangle.Empty;
100                         marshal_free_list = new ArrayList(2);
101                         opacity = 0xffffffff;
102                         fixed_size = false;
103                 }
104
105                 public void Dispose() {
106                         expose_pending = false;
107                         nc_expose_pending = false;
108                         lock (windows) {
109                                 windows.Remove(client_window);
110                                 windows.Remove(whole_window);
111                         }
112                         for (int i = 0; i < marshal_free_list.Count; i++) {
113                                 Marshal.FreeHGlobal((IntPtr)marshal_free_list[i]);
114                         }
115                         marshal_free_list.Clear();
116                 }
117                 #endregion
118
119                 #region Static Methods
120                 public void SetObjectWindow(Hwnd obj, IntPtr window) {
121                         windows[window] = obj;
122                 }
123
124                 public static Hwnd ObjectFromWindow(IntPtr window) {
125                         Hwnd rv;
126                         lock (windows) {
127                                 rv = (Hwnd)windows[window];
128                         }
129                         return rv;
130                 }
131
132                 public static Hwnd ObjectFromHandle(IntPtr handle) {
133                         //return (Hwnd)(((GCHandle)handle).Target);
134                         Hwnd rv;
135                         lock (windows) {
136                                 rv = (Hwnd)windows[handle];
137                         }
138                         return rv;
139                 }
140
141                 public static IntPtr HandleFromObject(Hwnd obj) {
142                         return obj.handle;
143                 }
144
145                 public static Hwnd GetObjectFromWindow(IntPtr window) {
146                         Hwnd rv;
147                         lock (windows) {
148                                 rv = (Hwnd)windows[window];
149                         }
150                         return rv;
151                 }
152
153                 public static IntPtr GetHandleFromWindow(IntPtr window) {
154                         Hwnd    hwnd;
155
156                         lock (windows) {
157                                 hwnd = (Hwnd)windows[window];
158                         }
159                         if (hwnd != null) {
160                                 return hwnd.handle;
161                         } else {
162                                 return IntPtr.Zero;
163                         }
164                 }
165
166                 public static Rectangle GetWindowRectangle(FormBorderStyle border_style,
167                                 Menu menu, TitleStyle title_style, int caption_height,
168                                 int tool_caption_height, Rectangle client_rect)
169                 {
170                         Rectangle       rect;
171
172                         rect = new Rectangle(client_rect.Location, client_rect.Size);
173
174                         if (menu != null) {
175                                 int menu_height = menu.Rect.Height;
176                                 if (menu_height == 0) {
177                                         Graphics g;
178
179                                         g = Graphics.FromImage(bmp);
180                                         menu_height = ThemeEngine.Current.CalcMenuBarSize(g, menu, client_rect.Width);
181                                         g.Dispose();
182                                 }
183
184                                 rect.Y -= menu_height;
185                                 rect.Height += menu_height;
186                         }
187
188                         if (border_style == FormBorderStyle.Fixed3D) {
189                                 Size border_3D_size = ThemeEngine.Current.Border3DSize;
190
191                                 rect.X -= border_3D_size.Width;
192                                 rect.Y -= border_3D_size.Height;
193                                 rect.Width += border_3D_size.Width * 2;
194                                 rect.Height += border_3D_size.Height * 2;
195                         } else if (border_style == FormBorderStyle.FixedSingle) {
196                                 rect.X -= 1;
197                                 rect.Y -= 1;
198                                 rect.Width += 2;
199                                 rect.Height += 2;
200                         }
201
202                         return rect;
203                 }
204
205                 public static Rectangle GetClientRectangle(FormBorderStyle border_style, Menu menu, TitleStyle title_style, int caption_height, int tool_caption_height, int width, int height) {
206                         Rectangle rect;
207
208                         rect = new Rectangle(0, 0, width, height);
209
210                         if (menu != null) {
211                                 int menu_height = menu.Rect.Height;
212                                 rect.Y += menu_height;
213                                 rect.Height -= menu_height;
214                         }
215
216                         if (border_style == FormBorderStyle.Fixed3D) {
217                                 Size border_3D_size = ThemeEngine.Current.Border3DSize;
218
219                                 rect.X += border_3D_size.Width;
220                                 rect.Y += border_3D_size.Height;
221                                 rect.Width -= border_3D_size.Width * 2;
222                                 rect.Height -= border_3D_size.Height * 2;
223                         } else if (border_style == FormBorderStyle.FixedSingle) {
224                                 rect.X += 1;
225                                 rect.Y += 1;
226                                 rect.Width -= 2;
227                                 rect.Height -= 2;
228                         }
229
230                         return rect;
231                 }
232                 #endregion      // Static Methods
233
234                 #region Instance Properties
235                 public FormBorderStyle BorderStyle {
236                         get {
237                                 return border_style;
238                         }
239
240                         set {
241                                 border_style = value;
242                         }
243                 }
244
245                 public Graphics ClientDC {
246                         get {
247                                 return client_dc;
248                         }
249
250                         set {
251                                 client_dc = value;
252                         }
253                 }
254
255                 public Graphics NonClientDC {
256                         get { return non_client_dc; }
257                         set { non_client_dc = value; }
258                 }
259
260                 public Rectangle ClientRect {
261                         get {
262                                 if (client_rectangle == Rectangle.Empty) {
263                                         return DefaultClientRect;
264                                 }
265                                 return client_rectangle;
266                         }
267
268                         set {
269                                 client_rectangle = value;
270                         }
271                 }
272
273                 public IntPtr ClientWindow {
274                         get {
275                                 return client_window;
276                         }
277
278                         set {
279                                 client_window = value;
280                                 handle = value;
281
282                                 lock (windows) {
283                                         if (windows[client_window] == null) {
284                                                 windows[client_window] = this;
285                                         }
286                                 }
287                         }
288                 }
289
290                 public Region UserClip {
291                         get {
292                                 return user_clip;
293                         }
294
295                         set {
296                                 user_clip = value;
297                         }
298                 }
299
300                 public Rectangle DefaultClientRect {
301                         get {
302                                 // We pass a Zero for the menu handle so the menu size is
303                                 // not computed this is done via an WM_NCCALC
304                                 return GetClientRectangle (border_style, null, title_style,
305                                                 caption_height, tool_caption_height, width, height);
306                         }
307                 }
308
309                 public bool ExposePending {
310                         get {
311                                 return expose_pending;
312                         }
313
314                         set {
315                                 expose_pending = value;
316                         }
317                 }
318
319                 public IntPtr Handle {
320                         get {
321                                 if (handle == IntPtr.Zero) {
322                                         throw new ArgumentNullException("Handle", "Handle is not yet assigned, need a ClientWindow");
323                                 }
324                                 return handle;
325                         }
326                 }
327
328                 public int Height {
329                         get {
330                                 return height;
331                         }
332
333                         set {
334                                 height = value;
335                         }
336                 }
337
338                 public Menu Menu {
339                         get {
340                                 return menu;
341                         }
342
343                         set {
344                                 menu = value;
345                         }
346                 }
347
348                 public bool Reparented {
349                         get {
350                                 return reparented;
351                         }
352
353                         set {
354                                 reparented = value;
355                         }
356                 }
357
358                 public uint Opacity {
359                         get {
360                                 return opacity;
361                         }
362
363                         set {
364                                 opacity = value;
365                         }
366                 }
367
368                 public XEventQueue Queue {
369                         get {
370                                 return queue;
371                         }
372
373                         set {
374                                 queue = value;
375                         }
376                 }
377
378                 public bool Enabled {
379                         get {
380                                 if (!enabled) {
381                                         return false;
382                                 }
383
384                                 if (parent != null) {
385                                         return parent.Enabled;
386                                 }
387
388                                 return true;
389                         }
390
391                         set {
392                                 enabled = value;
393                         }
394                 }
395
396                 public IntPtr EnabledHwnd {
397                         get {
398                                 if (Enabled || parent == null) {
399                                         return Handle;
400                                 }
401
402                                 return parent.EnabledHwnd;
403                         }
404                 }
405
406                 public Point MenuOrigin {
407                         get {
408                                 Point   pt;
409                                 Size    border_3D_size = ThemeEngine.Current.Border3DSize;
410
411                                 pt = new Point(0, 0);
412
413                                 if (border_style == FormBorderStyle.Fixed3D) {
414                                         pt.X += border_3D_size.Width;
415                                         pt.Y += border_3D_size.Height;
416                                 } else if (border_style == FormBorderStyle.FixedSingle) {
417                                         pt.X += 1;
418                                         pt.Y += 1;
419                                 }
420
421                                 if (this.title_style == TitleStyle.Normal)  {
422                                         pt.Y += caption_height;
423                                 } else if (this.title_style == TitleStyle.Normal)  {
424                                         pt.Y += tool_caption_height;
425                                 }
426
427                                 return pt;
428                         }
429                 }
430
431                 public Rectangle Invalid {
432                         get {
433                                 if (invalid_list.Count == 0)
434                                         return Rectangle.Empty;
435
436                                 Rectangle result = (Rectangle)invalid_list[0];
437                                 for (int i = 1; i < invalid_list.Count; i ++) {
438                                         result = Rectangle.Union (result, (Rectangle)invalid_list[i]);
439                                 }
440                                 return result;
441                         }
442                 }
443
444                 public Rectangle[] ClipRectangles {
445                         get {
446                                 return (Rectangle[]) invalid_list.ToArray (typeof (Rectangle));
447                         }
448                 }
449
450                 public Rectangle NCInvalid {
451                         get { return nc_invalid; }
452                         set { nc_invalid = value; }
453
454                 }
455
456                 public bool NCExposePending {
457                         get {
458                                 return nc_expose_pending;
459                         }
460
461                         set {
462                                 nc_expose_pending = value;
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                                 lock (windows) {
533                                         if (windows[whole_window] == null) {
534                                                 windows[whole_window] = this;
535                                         }
536                                 }
537                         }
538                 }
539
540                 public int Width {
541                         get {
542                                 return width;
543                         }
544
545                         set {
546                                 width = value;
547                         }
548                 }
549
550                 public bool Visible {
551                         get {
552                                 return visible;
553                         }
554
555                         set {
556                                 visible = value;
557                         }
558                 }
559
560                 public int X {
561                         get {
562                                 return x;
563                         }
564
565                         set {
566                                 x = value;
567                         }
568                 }
569
570                 public int Y {
571                         get {
572                                 return y;
573                         }
574
575                         set {
576                                 y = value;
577                         }
578                 }
579
580                 #endregion      // Instance properties
581
582                 #region Methods
583                 public void AddInvalidArea(int x, int y, int width, int height) {
584                         AddInvalidArea(new Rectangle(x, y, width, height));
585                 }
586
587                 public void AddInvalidArea(Rectangle rect) {
588                         ArrayList tmp = new ArrayList ();
589                         foreach (Rectangle r in invalid_list) {
590                                 if (!rect.Contains (r)) {
591                                         tmp.Add (r);
592                                 }
593                         }
594                         tmp.Add (rect);
595                         invalid_list = tmp;
596                 }
597
598                 public void ClearInvalidArea() {
599                         invalid_list.Clear();
600                         expose_pending = false;
601                 }
602
603                 public void AddNcInvalidArea(int x, int y, int width, int height) {
604                         if (nc_invalid == Rectangle.Empty) {
605                                 nc_invalid = new Rectangle (x, y, width, height);
606                                 return;
607                         }
608
609                         int right, bottom;
610                         right = Math.Max (nc_invalid.Right, x + width);
611                         bottom = Math.Max (nc_invalid.Bottom, y + height);
612                         nc_invalid.X = Math.Min (nc_invalid.X, x);
613                         nc_invalid.Y = Math.Min (nc_invalid.Y, y);
614
615                         nc_invalid.Width = right - nc_invalid.X;
616                         nc_invalid.Height = bottom - nc_invalid.Y;
617                 }
618
619                 public void AddNcInvalidArea(Rectangle rect) {
620                         if (nc_invalid == Rectangle.Empty) {
621                                 nc_invalid = rect;
622                                 return;
623                         }
624                         nc_invalid = Rectangle.Union (nc_invalid, rect);
625                 }
626
627                 public void ClearNcInvalidArea() {
628                         nc_invalid = Rectangle.Empty;
629                         nc_expose_pending = false;
630                 }
631
632                 public override string ToString() {
633                         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);
634                 }
635
636                 #endregion      // Methods
637         }
638 }