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