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