2007-01-10 Jonathan Pobst <jpobst@novell.com>
[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                         
201                         if (border_size.Width != 0) {
202                                 rect.X -= border_size.Width;
203                                 rect.Width += border_size.Width * 2;
204                         }
205
206                         if (border_size.Height != 0) {
207                                 rect.Y -= border_size.Height;
208                                 rect.Height += border_size.Height * 2;
209                         }
210
211                         return rect;
212                 }
213
214                 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) {
215                         Rectangle rect;
216
217                         rect = new Rectangle(0, 0, width, height);
218
219                         if (menu != null) {
220                                 int menu_height = menu.Rect.Height;
221                                 rect.Y += menu_height;
222                                 rect.Height -= menu_height;
223                         }
224
225                         Size border_size = new Size (0, 0);
226                         
227                         if (border_static)
228                                 border_size = ThemeEngine.Current.BorderStaticSize;
229                         else if (border_style == FormBorderStyle.FixedSingle)
230                                 border_size = ThemeEngine.Current.BorderSize;
231                         else if (border_style == FormBorderStyle.Fixed3D)
232                                 border_size = ThemeEngine.Current.Border3DSize;
233
234                         if (border_size.Width != 0) {
235                                 rect.X += border_size.Width;
236                                 rect.Width -= border_size.Width * 2;
237                         }
238
239                         if (border_size.Height != 0) {
240                                 rect.Y += border_size.Height;
241                                 rect.Height -= border_size.Height * 2;
242                         }
243                         
244                         return rect;
245                 }
246                 #endregion      // Static Methods
247
248                 #region Instance Properties
249                 public FormBorderStyle BorderStyle {
250                         get {
251                                 return border_style;
252                         }
253
254                         set {
255                                 border_style = value;
256                         }
257                 }
258
259                 public Rectangle ClientRect {
260                         get {
261                                 if (client_rectangle == Rectangle.Empty) {
262                                         return DefaultClientRect;
263                                 }
264                                 return client_rectangle;
265                         }
266
267                         set {
268                                 client_rectangle = value;
269                         }
270                 }
271
272                 public IntPtr ClientWindow {
273                         get {
274                                 return client_window;
275                         }
276
277                         set {
278                                 client_window = value;
279                                 handle = value;
280
281                                 zombie = false;
282
283                                 if (client_window != IntPtr.Zero) {
284                                         lock (windows) {
285                                                 if (windows[client_window] == null) {
286                                                         windows[client_window] = this;
287                                                 }
288                                         }
289                                 }
290                         }
291                 }
292
293                 public Region UserClip {
294                         get {
295                                 return user_clip;
296                         }
297
298                         set {
299                                 user_clip = value;
300                         }
301                 }
302
303                 public Rectangle DefaultClientRect {
304                         get {
305                                 // We pass a Zero for the menu handle so the menu size is
306                                 // not computed this is done via an WM_NCCALC
307                                 return GetClientRectangle (border_style, border_static, null, title_style,
308                                                 caption_height, tool_caption_height, width, height);
309                         }
310                 }
311
312                 public bool ExposePending {
313                         get {
314                                 return expose_pending;
315                         }
316                 }
317
318                 public IntPtr Handle {
319                         get {
320                                 if (handle == IntPtr.Zero) {
321                                         throw new ArgumentNullException("Handle", "Handle is not yet assigned, need a ClientWindow");
322                                 }
323                                 return handle;
324                         }
325                 }
326
327                 public int Height {
328                         get {
329                                 return height;
330                         }
331
332                         set {
333                                 height = value;
334                         }
335                 }
336
337                 public Menu Menu {
338                         get {
339                                 return menu;
340                         }
341
342                         set {
343                                 menu = value;
344                         }
345                 }
346
347                 public bool Reparented {
348                         get {
349                                 return reparented;
350                         }
351
352                         set {
353                                 reparented = value;
354                         }
355                 }
356
357                 public uint Opacity {
358                         get {
359                                 return opacity;
360                         }
361
362                         set {
363                                 opacity = value;
364                         }
365                 }
366
367                 public XEventQueue Queue {
368                         get {
369                                 return queue;
370                         }
371
372                         set {
373                                 queue = value;
374                         }
375                 }
376
377                 public bool Enabled {
378                         get {
379                                 if (!enabled) {
380                                         return false;
381                                 }
382
383                                 if (parent != null) {
384                                         return parent.Enabled;
385                                 }
386
387                                 return true;
388                         }
389
390                         set {
391                                 enabled = value;
392                         }
393                 }
394
395                 public IntPtr EnabledHwnd {
396                         get {
397                                 if (Enabled || parent == null) {
398                                         return Handle;
399                                 }
400
401                                 return parent.EnabledHwnd;
402                         }
403                 }
404
405                 public Point MenuOrigin {
406                         get {
407                                 Point   pt;
408                                 Size    border_3D_size = ThemeEngine.Current.Border3DSize;
409
410                                 pt = new Point(0, 0);
411
412                                 if (border_style == FormBorderStyle.Fixed3D) {
413                                         pt.X += border_3D_size.Width;
414                                         pt.Y += border_3D_size.Height;
415                                 } else if (border_style == FormBorderStyle.FixedSingle) {
416                                         pt.X += 1;
417                                         pt.Y += 1;
418                                 }
419
420                                 if (this.title_style == TitleStyle.Normal)  {
421                                         pt.Y += caption_height;
422                                 } else if (this.title_style == TitleStyle.Normal)  {
423                                         pt.Y += tool_caption_height;
424                                 }
425
426                                 return pt;
427                         }
428                 }
429
430                 public Rectangle Invalid {
431                         get {
432                                 if (invalid_list.Count == 0)
433                                         return Rectangle.Empty;
434
435                                 Rectangle result = (Rectangle)invalid_list[0];
436                                 for (int i = 1; i < invalid_list.Count; i ++) {
437                                         result = Rectangle.Union (result, (Rectangle)invalid_list[i]);
438                                 }
439                                 return result;
440                         }
441                 }
442
443                 public Rectangle[] ClipRectangles {
444                         get {
445                                 return (Rectangle[]) invalid_list.ToArray (typeof (Rectangle));
446                         }
447                 }
448
449                 public Rectangle NCInvalid {
450                         get { return nc_invalid; }
451                         set { nc_invalid = value; }
452
453                 }
454
455                 public bool NCExposePending {
456                         get {
457                                 return nc_expose_pending;
458                         }
459                 }
460
461                 public Hwnd Parent {
462                         get {
463                                 return parent;
464                         }
465
466                         set {
467                                 parent = value;
468                         }
469                 }
470
471                 public bool Mapped {
472                         get {
473                                 if (!mapped) {
474                                         return false;
475                                 }
476
477                                 if (parent != null) {
478                                         return parent.Mapped;
479                                 }
480
481                                 return true;
482                         }
483
484                         set {
485                                 mapped = value;
486                         }
487                 }
488
489                 public int CaptionHeight {
490                         get { return caption_height; }
491                         set { caption_height = value; }
492                 }
493
494                 public int ToolCaptionHeight {
495                         get { return tool_caption_height; }
496                         set { tool_caption_height = value; }
497                 }
498
499                 public TitleStyle TitleStyle {
500                         get {
501                                 return title_style;
502                         }
503
504                         set {
505                                 title_style = value;
506                         }
507                 }
508
509                 public object UserData {
510                         get {
511                                 return user_data;
512                         }
513
514                         set {
515                                 user_data = value;
516                         }
517                 }
518
519                 public IntPtr WholeWindow {
520                         get {
521                                 return whole_window;
522                         }
523
524                         set {
525                                 whole_window = value;
526
527                                 zombie = false;
528
529                                 if (whole_window != IntPtr.Zero) {
530                                         lock (windows) {
531                                                 if (windows[whole_window] == null) {
532                                                         windows[whole_window] = this;
533                                                 }
534                                         }
535                                 }
536                         }
537                 }
538
539                 public int Width {
540                         get {
541                                 return width;
542                         }
543
544                         set {
545                                 width = value;
546                         }
547                 }
548
549                 public bool Visible {
550                         get {
551                                 return visible;
552                         }
553
554                         set {
555                                 visible = value;
556                         }
557                 }
558
559                 public int X {
560                         get {
561                                 return x;
562                         }
563
564                         set {
565                                 x = value;
566                         }
567                 }
568
569                 public int Y {
570                         get {
571                                 return y;
572                         }
573
574                         set {
575                                 y = value;
576                         }
577                 }
578
579                 #endregion      // Instance properties
580
581                 #region Methods
582                 public void AddInvalidArea(int x, int y, int width, int height) {
583                         AddInvalidArea(new Rectangle(x, y, width, height));
584                 }
585
586                 public void AddInvalidArea(Rectangle rect) {
587                         ArrayList tmp = new ArrayList ();
588                         foreach (Rectangle r in invalid_list) {
589                                 if (!rect.Contains (r)) {
590                                         tmp.Add (r);
591                                 }
592                         }
593                         tmp.Add (rect);
594                         invalid_list = tmp;
595                 }
596
597                 public void ClearInvalidArea() {
598                         invalid_list.Clear();
599                         expose_pending = false;
600                 }
601
602                 public void AddNcInvalidArea(int x, int y, int width, int height) {
603                         if (nc_invalid == Rectangle.Empty) {
604                                 nc_invalid = new Rectangle (x, y, width, height);
605                                 return;
606                         }
607
608                         int right, bottom;
609                         right = Math.Max (nc_invalid.Right, x + width);
610                         bottom = Math.Max (nc_invalid.Bottom, y + height);
611                         nc_invalid.X = Math.Min (nc_invalid.X, x);
612                         nc_invalid.Y = Math.Min (nc_invalid.Y, y);
613
614                         nc_invalid.Width = right - nc_invalid.X;
615                         nc_invalid.Height = bottom - nc_invalid.Y;
616                 }
617
618                 public void AddNcInvalidArea(Rectangle rect) {
619                         if (nc_invalid == Rectangle.Empty) {
620                                 nc_invalid = rect;
621                                 return;
622                         }
623                         nc_invalid = Rectangle.Union (nc_invalid, rect);
624                 }
625
626                 public void ClearNcInvalidArea() {
627                         nc_invalid = Rectangle.Empty;
628                         nc_expose_pending = false;
629                 }
630
631                 public override string ToString() {
632                         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);
633                 }
634
635                 #endregion      // Methods
636         }
637 }