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