merge from trunk revisions 58933, 58935, 58936
[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 IntPtr         menu_handle;
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           zero_sized;
58                 internal Rectangle      invalid;
59                 internal bool           expose_pending;
60                 internal bool           nc_expose_pending;
61                 internal bool           configure_pending;
62                 internal Graphics       client_dc;
63                 internal object         user_data;
64                 internal Rectangle      client_rectangle;
65                 internal ArrayList      marshal_free_list;
66                 internal int            caption_height;
67                 internal int            tool_caption_height;
68                 #endregion      // Local Variables
69
70                 #region Constructors and destructors
71                 public Hwnd() {
72                         x = 0;
73                         y = 0;
74                         width = 0;
75                         height = 0;
76                         visible = false;
77                         menu_handle = IntPtr.Zero;
78                         border_style = FormBorderStyle.None;
79                         client_window = IntPtr.Zero;
80                         whole_window = IntPtr.Zero;
81                         handle = IntPtr.Zero;
82                         parent = null;
83                         invalid = Rectangle.Empty;
84                         expose_pending = false;
85                         nc_expose_pending = false;
86                         client_rectangle = Rectangle.Empty;
87                         marshal_free_list = new ArrayList(2);
88                 }
89
90                 public void Dispose() {
91                         windows[client_window] = null;
92                         windows[whole_window] = null;
93                         for (int i = 0; i < marshal_free_list.Count; i++) {
94                                 Marshal.FreeHGlobal((IntPtr)marshal_free_list[i]);
95                         }
96                         marshal_free_list.Clear();
97                 }
98                 #endregion
99
100                 #region Static Methods
101                 public void SetObjectWindow(Hwnd obj, IntPtr window) {
102                         windows[window] = obj;
103                 }
104
105                 public static Hwnd ObjectFromWindow(IntPtr window) {
106                         return (Hwnd)windows[window];
107                 }
108
109                 public static Hwnd ObjectFromHandle(IntPtr handle) {
110                         //return (Hwnd)(((GCHandle)handle).Target);
111                         return (Hwnd)windows[handle];
112                 }
113
114                 public static IntPtr HandleFromObject(Hwnd obj) {
115                         return obj.handle;
116                 }
117
118                 public static Hwnd GetObjectFromWindow(IntPtr window) {
119                         return (Hwnd)windows[window];
120                 }
121
122                 public static IntPtr GetHandleFromWindow(IntPtr window) {
123                         Hwnd    hwnd;
124
125                         hwnd = (Hwnd)windows[window];
126                         if (hwnd != null) {
127                                 return hwnd.handle;
128                         } else {
129                                 return IntPtr.Zero;
130                         }
131                 }
132
133                 public static Rectangle GetWindowRectangle(FormBorderStyle border_style,
134                                 IntPtr menu_handle, TitleStyle title_style, int caption_height,
135                                 int tool_caption_height, Rectangle client_rect)
136                 {
137                         Rectangle       rect;
138
139                         rect = new Rectangle(client_rect.Location, client_rect.Size);
140
141                         if (menu_handle != IntPtr.Zero) {
142                                 MenuAPI.MENU menu = MenuAPI.GetMenuFromID (menu_handle);
143                                 if (menu != null) {
144                                         int menu_height = menu.Height;
145                                         rect.Y -= menu_height;
146                                         rect.Height += menu_height;
147                                 } else
148                                         Console.WriteLine("Hwnd.GetWindowRectangle: No MENU for menu_handle = {0}", menu_handle);
149                         }
150
151                         if (border_style == FormBorderStyle.Fixed3D) {
152                                 rect.X -= 2;
153                                 rect.Y -= 2;
154                                 rect.Width += 4;
155                                 rect.Height += 4;
156                         } else if (border_style == FormBorderStyle.FixedSingle) {
157                                 rect.X -= 1;
158                                 rect.Y -= 1;
159                                 rect.Width += 2;
160                                 rect.Height += 2;
161                         } else if ((int) border_style == 0xFFFF) {
162                                 rect.X -= 3;
163                                 rect.Y -= 3;
164                                 rect.Width += 6;
165                                 rect.Height += 6;
166                         }
167
168                         if (title_style == TitleStyle.Normal) {
169                                 rect.Y -= caption_height;
170                                 rect.Height += caption_height;
171                         } else if (title_style == TitleStyle.Tool) {
172                                 rect.Y -= tool_caption_height;
173                                 rect.Height += tool_caption_height;
174                         }
175
176                         return rect;
177                 }
178
179                 public static Rectangle GetClientRectangle(FormBorderStyle border_style, IntPtr menu_handle, TitleStyle title_style, int caption_height, int tool_caption_height, int width, int height) {
180                         Rectangle rect;
181
182                         rect = new Rectangle(0, 0, width, height);
183
184                         /*
185                         if (menu_handle != IntPtr.Zero) {
186                                 MenuAPI.MENU menu = MenuAPI.GetMenuFromID (menu_handle);
187                                 if (menu != null) {
188                                         int menu_height = menu.Height;
189                                         rect.Y += menu_height;
190                                         rect.Height -= menu_height;
191                                 } else
192                                         Console.WriteLine("Hwnd.GetClientRectangle: No MENU for menu_handle = {0}", menu_handle);
193                         }
194                         */
195                         
196                         if (border_style == FormBorderStyle.Fixed3D) {
197                                 rect.X += 2;
198                                 rect.Y += 2;
199                                 rect.Width -= 4;
200                                 rect.Height -= 4;
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                                 return GetClientRectangle (border_style, menu_handle, title_style,
277                                                 caption_height, tool_caption_height, width, height);
278                         }
279                 }
280
281                 public bool ExposePending {
282                         get {
283                                 return expose_pending;
284                         }
285
286                         set {
287                                 expose_pending = value;
288                         }
289                 }
290
291                 public IntPtr Handle {
292                         get {
293                                 if (handle == IntPtr.Zero) {
294                                         throw new ArgumentNullException("Handle", "Handle is not yet assigned, need a ClientWindow");
295                                 }
296                                 return handle;
297                         }
298                 }
299
300                 public int Height {
301                         get {
302                                 return height;
303                         }
304
305                         set {
306                                 height = value;
307                         }
308                 }
309
310                 public IntPtr MenuHandle {
311                         get {
312                                 return menu_handle;
313                         }
314
315                         set {
316                                 menu_handle = value;
317                         }
318                 }
319
320                 public Point MenuOrigin {
321                         get {
322                                 Point   pt;
323
324                                 pt = new Point(0, 0);
325
326                                 if (border_style == FormBorderStyle.Fixed3D) {
327                                         pt.X += 2;
328                                         pt.Y += 2;
329                                 } else if (border_style == FormBorderStyle.FixedSingle) {
330                                         pt.X += 1;
331                                         pt.Y += 1;
332                                 }
333
334                                 if (this.title_style == TitleStyle.Normal)  {
335                                         pt.Y += caption_height;
336                                 } else if (this.title_style == TitleStyle.Normal)  {
337                                         pt.Y += tool_caption_height;
338                                 }
339
340                                 return pt;
341                         }
342                 }
343                 public Rectangle Invalid {
344                         get {
345                                 return invalid;
346                         }
347
348                         set {
349                                 invalid = value;
350                         }
351                 }
352
353                 public bool NCExposePending {
354                         get {
355                                 return nc_expose_pending;
356                         }
357
358                         set {
359                                 nc_expose_pending = value;
360                         }
361                 }
362
363                 public Hwnd Parent {
364                         get {
365                                 return parent;
366                         }
367
368                         set {
369                                 parent = value;
370                         }
371                 }
372
373                 public int CaptionHeight {
374                         get { return caption_height; }
375                         set { caption_height = value; }
376                 }
377
378                 public int ToolCaptionHeight {
379                         get { return tool_caption_height; }
380                         set { tool_caption_height = value; }
381                 }
382
383                 public TitleStyle TitleStyle {
384                         get {
385                                 return title_style;
386                         }
387
388                         set {
389                                 title_style = value;
390                         }
391                 }
392
393                 public object UserData {
394                         get {
395                                 return user_data;
396                         }
397
398                         set {
399                                 user_data = value;
400                         }
401                 }
402
403                 public IntPtr WholeWindow {
404                         get {
405                                 return whole_window;
406                         }
407
408                         set {
409                                 whole_window = value;
410
411                                 if (windows[whole_window] == null) {
412                                         windows[whole_window] = this;
413                                 }
414                         }
415                 }
416
417                 public int Width {
418                         get {
419                                 return width;
420                         }
421
422                         set {
423                                 width = value;
424                         }
425                 }
426
427                 public bool Visible {
428                         get {
429                                 return visible;
430                         }
431
432                         set {
433                                 visible = value;
434                         }
435                 }
436
437                 public int X {
438                         get {
439                                 return x;
440                         }
441
442                         set {
443                                 x = value;
444                         }
445                 }
446
447                 public int Y {
448                         get {
449                                 return y;
450                         }
451
452                         set {
453                                 y = value;
454                         }
455                 }
456                 #endregion      // Instance properties
457
458                 #region Methods
459                 public void AddInvalidArea(int x, int y, int width, int height) {
460                         if (invalid == Rectangle.Empty) {
461                                 invalid = new Rectangle (x, y, width, height);
462                                 return;
463                         }
464
465                         int right, bottom;
466                         right = Math.Max (invalid.Right, x + width);
467                         bottom = Math.Max (invalid.Bottom, y + height);
468                         invalid.X = Math.Min (invalid.X, x);
469                         invalid.Y = Math.Min (invalid.Y, y);
470
471                         invalid.Width = right - invalid.X;
472                         invalid.Height = bottom - invalid.Y;
473                 }
474
475                 public void AddInvalidArea(Rectangle rect) {
476                         if (invalid == Rectangle.Empty) {
477                                 invalid = rect;
478                                 return;
479                         }
480                         invalid = Rectangle.Union (invalid, rect);
481                 }
482
483                 public void ClearInvalidArea() {
484                         invalid = Rectangle.Empty;
485                         expose_pending = false;
486                 }
487                 #endregion      // Methods
488         }
489 }