2006-01-25 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 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 bool           expose_pending;
62                 internal bool           nc_expose_pending;
63                 internal bool           configure_pending;
64                 internal bool           reparented;
65                 internal Graphics       client_dc;
66                 internal object         user_data;
67                 internal Rectangle      client_rectangle;
68                 internal ArrayList      marshal_free_list;
69                 internal int            caption_height;
70                 internal int            tool_caption_height;
71                 #endregion      // Local Variables
72
73                 #region Constructors and destructors
74                 public Hwnd() {
75                         x = 0;
76                         y = 0;
77                         width = 0;
78                         height = 0;
79                         visible = false;
80                         menu = null;
81                         border_style = FormBorderStyle.None;
82                         client_window = IntPtr.Zero;
83                         whole_window = IntPtr.Zero;
84                         handle = IntPtr.Zero;
85                         parent = null;
86                         invalid = Rectangle.Empty;
87                         expose_pending = false;
88                         nc_expose_pending = false;
89                         enabled = true;
90                         reparented = false;
91                         client_rectangle = Rectangle.Empty;
92                         marshal_free_list = new ArrayList(2);
93                         opacity = 0xffffffff;
94                 }
95
96                 public void Dispose() {
97                         windows[client_window] = null;
98                         windows[whole_window] = null;
99                         for (int i = 0; i < marshal_free_list.Count; i++) {
100                                 Marshal.FreeHGlobal((IntPtr)marshal_free_list[i]);
101                         }
102                         marshal_free_list.Clear();
103                 }
104                 #endregion
105
106                 #region Static Methods
107                 public void SetObjectWindow(Hwnd obj, IntPtr window) {
108                         windows[window] = obj;
109                 }
110
111                 public static Hwnd ObjectFromWindow(IntPtr window) {
112                         return (Hwnd)windows[window];
113                 }
114
115                 public static Hwnd ObjectFromHandle(IntPtr handle) {
116                         //return (Hwnd)(((GCHandle)handle).Target);
117                         return (Hwnd)windows[handle];
118                 }
119
120                 public static IntPtr HandleFromObject(Hwnd obj) {
121                         return obj.handle;
122                 }
123
124                 public static Hwnd GetObjectFromWindow(IntPtr window) {
125                         return (Hwnd)windows[window];
126                 }
127
128                 public static IntPtr GetHandleFromWindow(IntPtr window) {
129                         Hwnd    hwnd;
130
131                         hwnd = (Hwnd)windows[window];
132                         if (hwnd != null) {
133                                 return hwnd.handle;
134                         } else {
135                                 return IntPtr.Zero;
136                         }
137                 }
138
139                 public static Rectangle GetWindowRectangle(FormBorderStyle border_style,
140                                 Menu menu, TitleStyle title_style, int caption_height,
141                                 int tool_caption_height, Rectangle client_rect)
142                 {
143                         Rectangle       rect;
144
145                         rect = new Rectangle(client_rect.Location, client_rect.Size);
146
147                         if (menu != null) {
148                                 int menu_height = menu.Rect.Height;
149                                 rect.Y -= menu_height;
150                                 rect.Height += menu_height;
151                         }
152
153                         if (border_style == FormBorderStyle.Fixed3D) {
154                                 Size border_3D_size = ThemeEngine.Current.Border3DSize;
155
156                                 rect.X -= border_3D_size.Width;
157                                 rect.Y -= border_3D_size.Height;
158                                 rect.Width += border_3D_size.Width * 2;
159                                 rect.Height += border_3D_size.Height * 2;
160                         } else if (border_style == FormBorderStyle.FixedSingle) {
161                                 rect.X -= 1;
162                                 rect.Y -= 1;
163                                 rect.Width += 2;
164                                 rect.Height += 2;
165                         } else if ((int) border_style == 0xFFFF) {
166                                 rect.X -= 3;
167                                 rect.Y -= 3;
168                                 rect.Width += 6;
169                                 rect.Height += 6;
170                         }
171
172                         if (title_style == TitleStyle.Normal) {
173                                 rect.Y -= caption_height;
174                                 rect.Height += caption_height;
175                         } else if (title_style == TitleStyle.Tool) {
176                                 rect.Y -= tool_caption_height;
177                                 rect.Height += tool_caption_height;
178                         }
179
180                         return rect;
181                 }
182
183                 public static Rectangle GetClientRectangle(FormBorderStyle border_style, Menu menu, TitleStyle title_style, int caption_height, int tool_caption_height, int width, int height) {
184                         Rectangle rect;
185
186                         rect = new Rectangle(0, 0, width, height);
187
188                         if (menu != null) {
189                                 int menu_height = menu.Rect.Height;
190                                 rect.Y += menu_height;
191                                 rect.Height -= menu_height;
192                         }
193                         
194                         if (border_style == FormBorderStyle.Fixed3D) {
195                                 Size border_3D_size = ThemeEngine.Current.Border3DSize;
196
197                                 rect.X += border_3D_size.Width;
198                                 rect.Y += border_3D_size.Height;
199                                 rect.Width -= border_3D_size.Width * 2;
200                                 rect.Height -= border_3D_size.Height * 2;
201                         } else if (border_style == FormBorderStyle.FixedSingle) {
202                                 rect.X += 1;
203                                 rect.Y += 1;
204                                 rect.Width -= 2;
205                                 rect.Height -= 2;
206                         } else if ((int) border_style == 0xFFFF) {
207                                 rect.X += 3;
208                                 rect.Y += 3;
209                                 rect.Width -= 6;
210                                 rect.Height -= 6;
211                         }
212
213                         if (title_style == TitleStyle.Normal)  {
214                                 rect.Y += caption_height;
215                                 rect.Height -= caption_height;
216                         } else if (title_style == TitleStyle.Tool)  {
217                                 rect.Y += tool_caption_height;
218                                 rect.Height -= tool_caption_height;
219                         }
220
221                         return rect;
222                 }
223                 #endregion      // Static Methods
224
225                 #region Instance Properties
226                 public FormBorderStyle BorderStyle {
227                         get {
228                                 return border_style;
229                         }
230
231                         set {
232                                 border_style = value;
233                         }
234                 }
235
236                 public Graphics ClientDC {
237                         get {
238                                 return client_dc;
239                         }
240
241                         set {
242                                 client_dc = value;
243                         }
244                 }
245
246                 public Rectangle ClientRect {
247                         get {
248                                 if (client_rectangle == Rectangle.Empty) {
249                                         return DefaultClientRect;
250                                 }
251                                 return client_rectangle;
252                         }
253
254                         set {
255                                 client_rectangle = value;
256                         }
257                 }
258
259                 public IntPtr ClientWindow {
260                         get {
261                                 return client_window;
262                         }
263
264                         set {
265                                 client_window = value;
266                                 handle = value;
267
268                                 if (windows[client_window] == null) {
269                                         windows[client_window] = this;
270                                 }
271                         }
272                 }
273
274                 public Rectangle DefaultClientRect {
275                         get {
276                                 // We pass a Zero for the menu handle so the menu size is
277                                 // not computed this is done via an WM_NCCALC
278                                 return GetClientRectangle (border_style, null, title_style,
279                                                 caption_height, tool_caption_height, width, height);
280                         }
281                 }
282
283                 public bool ExposePending {
284                         get {
285                                 return expose_pending;
286                         }
287
288                         set {
289                                 expose_pending = value;
290                         }
291                 }
292
293                 public IntPtr Handle {
294                         get {
295                                 if (handle == IntPtr.Zero) {
296                                         throw new ArgumentNullException("Handle", "Handle is not yet assigned, need a ClientWindow");
297                                 }
298                                 return handle;
299                         }
300                 }
301
302                 public int Height {
303                         get {
304                                 return height;
305                         }
306
307                         set {
308                                 height = value;
309                         }
310                 }
311
312                 public Menu Menu {
313                         get {
314                                 return menu;
315                         }
316
317                         set {
318                                 menu = value;
319                         }
320                 }
321
322                 public bool Reparented {
323                         get {
324                                 return reparented;
325                         }
326
327                         set {
328                                 reparented = value;
329                         }
330                 }
331
332                 public uint Opacity {
333                         get {
334                                 return opacity;
335                         }
336
337                         set {
338                                 opacity = value;
339                         }
340                 }
341
342                 public bool Enabled {
343                         get {
344                                 if (!enabled) {
345                                         return false;
346                                 }
347
348                                 if (parent != null) {
349                                         return parent.Enabled;
350                                 }
351
352                                 return true;
353                         }
354
355                         set {
356                                 enabled = value;
357                         }
358                 }
359
360                 public IntPtr EnabledHwnd {
361                         get {
362                                 if (Enabled || parent == null) {
363                                         return Handle;
364                                 }
365
366                                 return parent.EnabledHwnd;
367                         }
368                 }
369
370                 public Point MenuOrigin {
371                         get {
372                                 Point   pt;
373                                 Size    border_3D_size = ThemeEngine.Current.Border3DSize;
374
375                                 pt = new Point(0, 0);
376
377                                 if (border_style == FormBorderStyle.Fixed3D) {
378                                         pt.X += border_3D_size.Width;
379                                         pt.Y += border_3D_size.Height;
380                                 } else if (border_style == FormBorderStyle.FixedSingle) {
381                                         pt.X += 1;
382                                         pt.Y += 1;
383                                 }
384
385                                 if (this.title_style == TitleStyle.Normal)  {
386                                         pt.Y += caption_height;
387                                 } else if (this.title_style == TitleStyle.Normal)  {
388                                         pt.Y += tool_caption_height;
389                                 }
390
391                                 return pt;
392                         }
393                 }
394                 public Rectangle Invalid {
395                         get {
396                                 return invalid;
397                         }
398
399                         set {
400                                 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                 #endregion      // Instance properties
508
509                 #region Methods
510                 public void AddInvalidArea(int x, int y, int width, int height) {
511                         if (invalid == Rectangle.Empty) {
512                                 invalid = new Rectangle (x, y, width, height);
513                                 return;
514                         }
515
516                         int right, bottom;
517                         right = Math.Max (invalid.Right, x + width);
518                         bottom = Math.Max (invalid.Bottom, y + height);
519                         invalid.X = Math.Min (invalid.X, x);
520                         invalid.Y = Math.Min (invalid.Y, y);
521
522                         invalid.Width = right - invalid.X;
523                         invalid.Height = bottom - invalid.Y;
524                 }
525
526                 public void AddInvalidArea(Rectangle rect) {
527                         if (invalid == Rectangle.Empty) {
528                                 invalid = rect;
529                                 return;
530                         }
531                         invalid = Rectangle.Union (invalid, rect);
532                 }
533
534                 public void ClearInvalidArea() {
535                         invalid = Rectangle.Empty;
536                         expose_pending = false;
537                 }
538
539                 public override string ToString() {
540                         return String.Format("Hwnd, ClientWindow:0x{0:X}, WholeWindow:0x{1:X}, Handle:0x{2:X}", client_window.ToInt32(), whole_window.ToInt32(), handle.ToInt32());
541                 }
542
543                 #endregion      // Methods
544         }
545 }