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