* TabControl.cs: Show the tooltip depending on the value
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / NativeWindow.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) 2004-2008 Novell, Inc.
21 //
22 // Authors:
23 //      Peter Dennis Bartok     pbartok@novell.com
24 //      Ivan N. Zlatev          <contact@i-nz.net>
25 //
26
27
28 // COMPLETE
29
30 //#define ExternalExceptionHandler
31
32 using System.Runtime.Remoting;
33 using System.Runtime.InteropServices;
34 using System.Runtime.CompilerServices;
35 using System.Threading;
36 using System.Collections;
37 using System.Diagnostics;
38
39 namespace System.Windows.Forms
40 {
41         public class NativeWindow : MarshalByRefObject
42 #if NET_2_0
43                 , IWin32Window
44 #endif
45         {
46                 IntPtr window_handle = IntPtr.Zero;
47                 static Hashtable window_collection = new Hashtable();
48
49                 [ThreadStatic]
50                 static NativeWindow WindowCreating;
51
52                 #region Public Constructors
53                 public NativeWindow()
54                 {
55                         window_handle=IntPtr.Zero;
56                 }
57                 #endregion      // Public Constructors
58
59                 #region Public Instance Properties
60                 public IntPtr Handle {
61                         get {
62                                 return window_handle;
63                         }
64                 }
65                 #endregion      // Public Instance Properties
66
67                 #region Public Static Methods
68                 public static NativeWindow FromHandle(IntPtr handle)
69                 {
70                         return FindFirstInTable (handle);
71                 }
72                 #endregion      // Public Static Methods
73
74                 #region Private and Internal Methods
75                 internal void InvalidateHandle()
76                 {
77                         RemoveFromTable (this);
78                         window_handle = IntPtr.Zero;
79                 }
80                 #endregion
81
82                 #region Public Instance Methods
83                 public void AssignHandle(IntPtr handle)
84                 {
85                         RemoveFromTable (this);
86                         window_handle = handle;
87                         AddToTable (this);
88                         OnHandleChange();
89                 }
90
91                 private static void AddToTable (NativeWindow window)
92                 {
93                         IntPtr handle = window.Handle;
94                         if (handle == IntPtr.Zero)
95                                 return;
96
97                         lock (window_collection) {
98                                 object current = window_collection[handle];
99                                 if (current == null) {
100                                         window_collection.Add (handle, window);
101                                 } else {
102                                         NativeWindow currentWindow = current as NativeWindow;
103                                         if (currentWindow != null) {
104                                                 if (currentWindow != window) {
105                                                         ArrayList windows = new ArrayList ();
106                                                         windows.Add (currentWindow);
107                                                         windows.Add (window);
108                                                         window_collection[handle] = windows;
109                                                 }
110                                         } else { // list of windows
111                                                 ArrayList windows = (ArrayList) window_collection[handle];
112                                                 if (!windows.Contains (window))
113                                                         windows.Add (window);
114                                         }
115                                 }
116                         }
117                 }
118
119                 private static void RemoveFromTable (NativeWindow window)
120                 {
121                         IntPtr handle = window.Handle;
122                         if (handle == IntPtr.Zero)
123                                 return;
124
125                         lock (window_collection) {
126                                 object current = window_collection[handle];
127                                 if (current != null) {
128                                         NativeWindow currentWindow = current as NativeWindow;
129                                         if (currentWindow != null) {
130                                                 window_collection.Remove (handle);
131                                         } else { // list of windows
132                                                 ArrayList windows = (ArrayList) window_collection[handle];
133                                                 windows.Remove (window);
134                                                 if (windows.Count == 0)
135                                                         window_collection.Remove (handle);
136                                                 else if (windows.Count == 1)
137                                                         window_collection[handle] = windows[0];
138                                         }
139                                 }
140                         }
141                 }
142
143                 private static NativeWindow FindFirstInTable (IntPtr handle)
144                 {
145                         if (handle == IntPtr.Zero)
146                                 return null;
147
148                         NativeWindow window = null;
149                         lock (window_collection) {
150                                 object current = window_collection[handle];
151                                 if (current != null) {
152                                         window = current as NativeWindow;
153                                         if (window == null) {
154                                                 ArrayList windows = (ArrayList) current;
155                                                 if (windows.Count > 0)
156                                                         window = (NativeWindow) windows[0];
157                                         }
158                                 }
159                         }
160                         return window;
161                 }
162
163                 public virtual void CreateHandle(CreateParams cp)
164                 {
165                         if (cp != null) {
166                                 WindowCreating = this;
167                                 window_handle=XplatUI.CreateWindow(cp);
168                                 WindowCreating = null;
169
170                                 if (window_handle != IntPtr.Zero)
171                                         AddToTable (this);
172                         }
173
174                 }
175
176                 public void DefWndProc(ref Message m)
177                 {
178                         m.Result=XplatUI.DefWndProc(ref m);
179                 }
180
181                 public virtual void DestroyHandle()
182                 {
183                         if (window_handle != IntPtr.Zero) {
184                                 XplatUI.DestroyWindow(window_handle);
185                         }
186                 }
187
188                 public virtual void ReleaseHandle()
189                 {
190                         RemoveFromTable (this);
191                         window_handle=IntPtr.Zero;
192                         OnHandleChange();
193                 }
194
195                 #endregion      // Public Instance Methods
196
197                 #region Protected Instance Methods
198                 ~NativeWindow()
199                 {
200                 }
201
202                 protected virtual void OnHandleChange()
203                 {
204                 }
205
206                 protected virtual void OnThreadException(Exception e)
207                 {
208                         Application.OnThreadException(e);
209                 }
210
211                 protected virtual void WndProc(ref Message m)
212                 {
213                         DefWndProc(ref m);
214                 }
215
216                 internal static IntPtr WndProc(IntPtr hWnd, Msg msg, IntPtr wParam, IntPtr lParam)
217                 {
218                         IntPtr result = IntPtr.Zero;
219                         Message m = new Message();
220                         m.HWnd = hWnd;
221                         m.Msg = (int)msg;
222                         m.WParam = wParam;
223                         m.LParam = lParam;
224                         m.Result = IntPtr.Zero;
225                                         
226 #if debug
227                         Console.WriteLine("NativeWindow.cs ({0}, {1}, {2}, {3}): result {4}", hWnd, msg, wParam, lParam, m.Result);
228 #endif
229                         NativeWindow window = null;
230                         
231                         try {
232                         object current = null;
233                         lock (window_collection) {
234                                 current = window_collection[hWnd];
235                         }
236
237                         window = current as NativeWindow;
238                         if (current == null)
239                                 window = EnsureCreated (window, hWnd);
240
241                         if (window != null) {
242                                 window.WndProc (ref m);
243                                 result = m.Result;
244                         } else if (current is ArrayList) {
245                                 ArrayList windows = (ArrayList) current;
246                                 lock (windows) {
247                                         if (windows.Count > 0) {
248                                                 window = EnsureCreated ((NativeWindow)windows[0], hWnd);
249                                                 window.WndProc (ref m);
250                                                 // the first one is the control's one. all others are synthetic,
251                                                 // so we want only the result from the control
252                                                 result = m.Result;
253                                                 for (int i=1; i < windows.Count; i++)
254                                                         ((NativeWindow)windows[i]).WndProc (ref m);
255                                         }
256                                 }
257                         } else {
258                                 result = XplatUI.DefWndProc (ref m);
259                         }
260                         }
261                         catch (Exception ex) {
262 #if !ExternalExceptionHandler
263                                 if (window != null)
264                                         window.OnThreadException (ex);
265 #else
266                                 throw;
267 #endif
268                         }
269                         #if debug
270                                 Console.WriteLine("NativeWindow.cs: Message {0}, result {1}", msg, m.Result);
271                         #endif
272
273                         return result;
274                 }
275
276                 private static NativeWindow EnsureCreated (NativeWindow window, IntPtr hWnd)
277                 {
278                         // we need to do this AssignHandle here instead of relying on
279                         // Control.WndProc to do it, because subclasses can override
280                         // WndProc, install their own WM_CREATE block, and look at
281                         // this.Handle, and it needs to be set.  Otherwise, we end up
282                         // recursively creating windows and emitting WM_CREATE.
283                         if (window == null && WindowCreating != null) {
284                                 window = WindowCreating;
285                                 WindowCreating = null;
286                                 if (window.Handle == IntPtr.Zero)
287                                         window.AssignHandle (hWnd);
288                         }
289                         return window;
290                 }
291                 #endregion      // Protected Instance Methods
292         }
293 }