31842b5a1b6792b71151527082e76a8b82c3521b
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / Application.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 - 2006 Novell, Inc.
21 //
22 // Authors:
23 //      Peter Bartok    pbartok@novell.com
24 //      Daniel Nauck    (dna(at)mono-project(dot)de)
25 //
26
27 // COMPLETE
28
29 #undef DebugRunLoop
30
31 using Microsoft.Win32;
32 using System;
33 using System.Drawing;
34 using System.ComponentModel;
35 using System.Collections;
36 using System.Diagnostics;
37 using System.Globalization;
38 using System.IO;
39 using System.Reflection;
40 using System.Runtime.InteropServices;
41 using System.Threading;
42 #if NET_2_0
43 using System.Text;
44 using System.Windows.Forms.VisualStyles;
45 #endif
46
47 namespace System.Windows.Forms {
48         public sealed class Application {
49                 internal class MWFThread {
50                         #region Fields
51                         private ApplicationContext      context;
52                         private bool                    messageloop_started;
53                         private bool                    handling_exception;
54                         private int                     thread_id;
55
56                         private static Hashtable        threads = new Hashtable();
57                         #endregion      // Fields
58
59                         #region Constructors
60                         private MWFThread() {
61                         }
62                         #endregion      // Constructors
63
64                         #region Properties
65                         public ApplicationContext Context {
66                                 get { return context; }
67                                 set { context = value; }
68                         }
69
70                         public bool MessageLoop {
71                                 get { return messageloop_started; }
72                                 set { messageloop_started = value; }
73                         }
74
75                         public bool HandlingException {
76                                 get { return handling_exception; }
77                                 set { handling_exception = value; }
78
79                         }
80
81                         public static int LoopCount {
82                                 get {
83                                         lock (threads) {
84                                                 int loops = 0;
85
86                                                 foreach (MWFThread thread in threads.Values) {
87                                                         if (thread.messageloop_started)
88                                                                 loops++;
89                                                 }
90
91                                                 return loops;
92                                         }
93                                 }
94                         }
95
96                         public static MWFThread Current {
97                                 get {
98                                         MWFThread       thread;
99
100                                         thread = null;
101                                         lock (threads) {
102                                                 thread = (MWFThread)threads[Thread.CurrentThread.GetHashCode()];
103                                                 if (thread == null) {
104                                                         thread = new MWFThread();
105                                                         thread.thread_id = Thread.CurrentThread.GetHashCode();
106                                                         threads[thread.thread_id] = thread;
107                                                 }
108                                         }
109
110                                         return thread;
111                                 }
112                         }
113                         #endregion      // Properties
114
115                         #region Methods
116                         public void Exit() {
117                                 if (context != null) {
118                                         context.ExitThread();
119                                 }
120                                 context = null;
121
122                                 if (Application.ThreadExit != null) {
123                                         Application.ThreadExit(null, EventArgs.Empty);
124                                 }
125
126                                 if (LoopCount == 0) {
127                                         if (Application.ApplicationExit != null) {
128                                                 Application.ApplicationExit(null, EventArgs.Empty);
129                                         }
130                                 }
131
132                                 ((MWFThread)threads[thread_id]).MessageLoop = false;
133                         }
134                         #endregion      // Methods
135                 }
136
137                 private static bool                     browser_embedded        = false;
138                 private static InputLanguage            input_language          = InputLanguage.CurrentInputLanguage;
139                 private static string                   safe_caption_format     = "{1} - {0} - {2}";
140                 private static ArrayList                message_filters         = new ArrayList();
141                 private static FormCollection           forms                   = new FormCollection ();
142
143 #if NET_2_0
144                 private static bool use_wait_cursor = false;
145                 private static ToolStrip keyboard_capture;
146                 private static VisualStyleState visual_style_state = VisualStyleState.ClientAndNonClientAreasEnabled;
147 #endif
148
149                 private Application () {
150                 }
151
152                 #region Private Methods
153                 internal static void CloseForms(Thread thread) {
154                         #if DebugRunLoop
155                                 Console.WriteLine("   CloseForms({0}) called", thread);
156                         #endif
157
158                         ArrayList forms_to_close = new ArrayList ();
159
160                         lock (forms) {
161                                 foreach (Form f in forms) {
162                                         if (thread == null || thread == f.creator_thread)
163                                                 forms_to_close.Add (f);
164                                 }
165
166                                 foreach (Form f in forms_to_close) {
167                                         #if DebugRunLoop
168                                                 Console.WriteLine("      Closing form {0}", f);
169                                         #endif
170                                         f.Dispose ();
171                                 }
172                         }
173                 }
174                 #endregion      // Private methods
175
176                 #region Public Static Properties
177                 public static bool AllowQuit {
178                         get {
179                                 return !browser_embedded;
180                         }
181                 }
182
183                 public static string CommonAppDataPath {
184                         get {
185                                 return Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
186                         }
187                 }
188
189                 public static RegistryKey CommonAppDataRegistry {
190                         get {
191                                 RegistryKey     key;
192
193                                 key = Registry.LocalMachine.OpenSubKey("Software\\" + Application.CompanyName + "\\" + Application.ProductName + "\\" + Application.ProductVersion, true);
194
195                                 return key;
196                         }
197                 }
198
199                 public static string CompanyName {
200                         get {
201                                 Assembly assembly = Assembly.GetEntryAssembly ();
202                                 if (assembly == null)
203                                         assembly = Assembly.GetCallingAssembly ();
204                                 if (assembly == null)
205                                         return string.Empty;
206                                         
207                                 AssemblyCompanyAttribute[] attrs = (AssemblyCompanyAttribute[]) assembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), true);
208                                 
209                                 if ((attrs != null) && attrs.Length>0) {
210                                         return attrs[0].Company;
211                                 }
212
213                                 return assembly.GetName().Name;
214                         }
215                 }
216
217                 public static CultureInfo CurrentCulture {
218                         get {
219                                 return Thread.CurrentThread.CurrentUICulture;
220                         }
221
222                         set {
223                                 
224                                 Thread.CurrentThread.CurrentUICulture=value;
225                         }
226                 }
227
228                 public static InputLanguage CurrentInputLanguage {
229                         get {
230                                 return input_language;
231                         }
232
233                         set {
234                                 input_language=value;
235                         }
236                 }
237
238                 public static string ExecutablePath {
239                         get {
240                                 return Assembly.GetEntryAssembly().Location;
241                         }
242                 }
243
244                 public static string LocalUserAppDataPath {
245                         get {
246                                 return Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), CompanyName), ProductName), ProductVersion);
247                         }
248                 }
249
250                 public static bool MessageLoop {
251                         get {
252                                 return MWFThread.Current.MessageLoop;
253                         }
254                 }
255
256                 public static string ProductName {
257                         get {
258                                 Assembly assembly = Assembly.GetEntryAssembly ();
259                                 if (assembly == null)
260                                         assembly = Assembly.GetCallingAssembly ();
261                                 if (assembly == null)
262                                         return string.Empty;
263                                         
264                                 AssemblyProductAttribute[] attrs = (AssemblyProductAttribute[]) assembly.GetCustomAttributes(typeof(AssemblyProductAttribute), true);
265                                 
266                                 if ((attrs != null) && attrs.Length>0) {
267                                         return attrs[0].Product;
268                                 }
269
270                                 return assembly.GetName ().Name;
271                         }
272                 }
273
274                 public static string ProductVersion {
275                         get {
276                                 String version;
277
278                                 Assembly assembly = Assembly.GetEntryAssembly ();
279                                 if (assembly == null)
280                                         assembly = Assembly.GetCallingAssembly ();
281                                 if (assembly == null)
282                                         return string.Empty;
283
284                                 version = assembly.GetName ().Version.ToString ();
285
286                                 return version;
287                         }
288                 }
289
290                 public static string SafeTopLevelCaptionFormat {
291                         get {
292                                 return safe_caption_format;
293                         }
294
295                         set {
296                                 safe_caption_format=value;
297                         }
298                 }
299
300                 public static string StartupPath {
301                         get {
302                                 return Path.GetDirectoryName(Application.ExecutablePath);
303                         }
304                 }
305
306                 public static string UserAppDataPath {
307                         get {
308                                 return Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), CompanyName), ProductName), ProductVersion);
309                         }
310                 }
311
312                 public static RegistryKey UserAppDataRegistry {
313                         get {
314                                 RegistryKey     key;
315
316                                 key = Registry.CurrentUser.OpenSubKey("Software\\" + Application.CompanyName + "\\" + Application.ProductName + "\\" + Application.ProductVersion, true);
317
318                                 return key;
319                         }
320                 }
321
322 #if NET_2_0
323
324                 public static bool UseWaitCursor {
325                         get {
326                                 return use_wait_cursor;
327                         }
328                         set {
329                                 use_wait_cursor = value;
330                                 if (use_wait_cursor) {
331                                         foreach (Form form in OpenForms) {
332                                                 form.Cursor = Cursors.WaitCursor;
333                                         }
334                                 }
335                         }
336                 }
337                 
338                 public static bool RenderWithVisualStyles {
339                       get {
340                                 if (VisualStyleInformation.IsSupportedByOS)
341                                 {
342                                         if (!VisualStyleInformation.IsEnabledByUser)
343                                                 return false;
344                                   
345                                         if (!XplatUI.ThemesEnabled)
346                                                 return false;
347                                   
348                                         if (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled)
349                                                 return true;
350                                   
351                                         if (Application.VisualStyleState == VisualStyleState.ClientAreaEnabled)
352                                                 return true;
353                                 }
354                                 
355                                 return false;
356                       }
357                 }
358
359                 public static VisualStyleState VisualStyleState {
360                         get { return Application.visual_style_state; }
361                         set { Application.visual_style_state = value; }
362                 }
363 #endif
364
365                 #endregion
366
367                 #region Public Static Methods
368                 public static void AddMessageFilter(IMessageFilter value) {
369                         lock (message_filters) {
370                                 message_filters.Add(value);
371                         }
372                 }
373
374                 public static void DoEvents() {
375                         XplatUI.DoEvents();
376                 }
377
378                 public static void EnableVisualStyles() {
379                         XplatUI.EnableThemes();
380                 }
381
382 #if NET_2_0
383                 //
384                 // If true, it uses GDI+, performance reasons were quoted
385                 //
386                 static internal bool use_compatible_text_rendering = true;
387                 
388                 public static void SetCompatibleTextRenderingDefault (bool defaultValue)
389                 {
390                         use_compatible_text_rendering = defaultValue;
391                 }
392
393                 public static FormCollection OpenForms {
394                         get {
395                                 return forms;
396                         }
397                 }
398
399                 [MonoNotSupported ("Empty stub.")]
400                 public static void SetUnhandledExceptionMode (UnhandledExceptionMode mode)
401                 {
402                         //FIXME: a stub to fill
403                 }
404
405                 public static void RaiseIdle (EventArgs e)
406                 {
407                         XplatUI.RaiseIdle (e);
408                 }
409                 
410                 public static void Restart ()
411                 {
412                         //FIXME: ClickOnce stuff using the Update or UpdateAsync methods.
413                         //FIXME: SecurityPermission: Restart () requires IsUnrestricted permission.
414
415                         if (Assembly.GetEntryAssembly () == null)
416                                 throw new NotSupportedException ("The method 'Restart' is not supported by this application type.");
417
418                         string mono_path = null;
419
420                         //Get mono path
421                         PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static | BindingFlags.NonPublic);
422                         MethodInfo get_gac = null;
423                         if (gac != null)
424                                 get_gac = gac.GetGetMethod (true);
425
426                         if (get_gac != null) {
427                                 string gac_path = Path.GetDirectoryName ((string)get_gac.Invoke (null, null));
428                                 string mono_prefix = Path.GetDirectoryName (Path.GetDirectoryName (gac_path));
429
430                                 if (XplatUI.RunningOnUnix) {
431                                         mono_path = Path.Combine (mono_prefix, "bin/mono");
432                                         if (!File.Exists (mono_path))
433                                                 mono_path = "mono";
434                                 } else {
435                                         mono_path = Path.Combine (mono_prefix, "bin\\mono.bat");
436
437                                         if (!File.Exists (mono_path))
438                                                 mono_path = Path.Combine (mono_prefix, "bin\\mono.exe");
439
440                                         if (!File.Exists (mono_path))
441                                                 mono_path = Path.Combine (mono_prefix, "mono\\mono\\mini\\mono.exe");
442
443                                         if (!File.Exists (mono_path))
444                                                 throw new FileNotFoundException (string.Format ("Windows mono path not found: '{0}'", mono_path));
445                                 }
446                         }
447
448                         //Get command line arguments
449                         StringBuilder argsBuilder = new StringBuilder ();
450                         string[] args = Environment.GetCommandLineArgs ();
451                         for (int i = 0; i < args.Length; i++)
452                         {
453                                 argsBuilder.Append (string.Format ("\"{0}\" ", args[i]));
454                         }
455                         string arguments = argsBuilder.ToString ();
456                         ProcessStartInfo procInfo = Process.GetCurrentProcess ().StartInfo;
457
458                         if (mono_path == null) { //it is .NET on Windows
459                                 procInfo.FileName = args[0];
460                                 procInfo.Arguments = arguments.Remove (0, args[0].Length + 3); //1 space and 2 quotes
461                         }
462                         else {
463                                 procInfo.Arguments = arguments;
464                                 procInfo.FileName = mono_path;
465                         }
466
467                         procInfo.WorkingDirectory = Environment.CurrentDirectory;
468
469                         Application.Exit ();
470                         Process.Start (procInfo);
471                 }
472 #endif
473
474                 public static void Exit() {
475                         XplatUI.PostQuitMessage(0);
476                         CloseForms(null);
477                 }
478
479                 public static void ExitThread() {
480                         CloseForms(Thread.CurrentThread);
481                         // this might not be right - need to investigate (somehow) if a WM_QUIT message is generated here
482                         XplatUI.PostQuitMessage(0);
483                 }
484
485                 public static ApartmentState OleRequired() {
486                         //throw new NotImplementedException("OLE Not supported by this System.Windows.Forms implementation");
487                         return ApartmentState.Unknown;
488                 }
489
490                 public static void OnThreadException(Exception t) {
491                         if (MWFThread.Current.HandlingException) {
492                                 /* we're already handling an exception and we got
493                                    another one?  print it out and exit, this means
494                                    we've got a runtime/SWF bug. */
495                                 Console.WriteLine (t);
496                                 // Don't use Application.Exit here, since it may cause a stack overflow
497                                 // in certain cases. It's however hard to reproduce since it seems to 
498                                 // be depending on when the GC kicks in.
499                                 Environment.Exit(1);
500                         }
501
502                         try {
503                                 MWFThread.Current.HandlingException = true;
504
505                                 if (Application.ThreadException != null) {
506                                         Application.ThreadException(null, new ThreadExceptionEventArgs(t));
507                                         return;
508                                 }
509
510                                 if (SystemInformation.UserInteractive) {
511                                         Form form = new ThreadExceptionDialog (t);
512                                         form.ShowDialog ();
513                                 } else {
514                                         Console.WriteLine (t.ToString ());
515                                         Application.Exit ();
516                                 }
517                         } finally {
518                                 MWFThread.Current.HandlingException = false;
519                         }
520                 }
521
522                 public static void RemoveMessageFilter(IMessageFilter filter) {
523                         lock (message_filters) {
524                                 message_filters.Remove(filter);
525                         }
526                 }
527
528                 public static void Run() {
529                         RunLoop(false, new ApplicationContext());
530                 }
531
532                 public static void Run(Form mainForm) {
533                         RunLoop(false, new ApplicationContext(mainForm));
534                 }
535
536                 public static void Run(ApplicationContext context) {
537                         RunLoop(false, context);
538                 }
539
540                 private static void DisableFormsForModalLoop (Queue toplevels, ApplicationContext context)
541                 {
542                         Form f;
543
544                         lock (forms) {
545                                 IEnumerator control = forms.GetEnumerator ();
546
547                                 while (control.MoveNext ()) {
548                                         f = (Form)control.Current;
549
550                                         // Don't disable the main form.
551                                         if (f == context.MainForm) {
552                                                 continue;
553                                         }
554
555                                         // Don't disable any children of the main form.
556                                         // These do not have to be MDI children.
557                                         Control current = f;
558                                         bool is_child_of_main = false; ;
559
560                                         do {
561                                                 if (current.Parent == context.MainForm) {
562                                                         is_child_of_main = true;
563                                                         break;
564                                                 }
565                                                 current = current.Parent;
566                                         } while (current != null);
567
568                                         if (is_child_of_main)
569                                                 continue;
570
571                                         // Disable the rest
572                                         if (f.IsHandleCreated && XplatUI.IsEnabled (f.Handle)) {
573 #if DebugRunLoop
574                                                                 Console.WriteLine("      Disabling form {0}", f);
575 #endif
576                                                 XplatUI.EnableWindow (f.Handle, false);
577                                                 toplevels.Enqueue (f);
578                                         }
579                                 }
580                         }
581                                 
582                 }
583                 
584                 
585                 private static void EnableFormsForModalLoop (Queue toplevels, ApplicationContext context)
586                 {
587                         while (toplevels.Count > 0) {
588 #if DebugRunLoop
589                                                 Console.WriteLine("      Re-Enabling form form {0}", toplevels.Peek());
590 #endif
591                                 Form c = (Form)toplevels.Dequeue ();
592                                 if (c.IsHandleCreated) {
593                                         XplatUI.EnableWindow (c.window.Handle, true);
594                                         context.MainForm = c;
595                                 }
596                         }
597 #if DebugRunLoop
598                                         Console.WriteLine("   Done with the re-enable");
599 #endif
600                 }
601
602                 internal static void RunLoop(bool Modal, ApplicationContext context) {
603                         Queue           toplevels;
604                         MSG             msg;
605                         Object          queue_id;
606                         MWFThread       thread;
607                         ApplicationContext previous_thread_context;
608                         
609                         thread = MWFThread.Current;
610
611                         /*
612                          * There is a NotWorking test for this, but since we are using this method both for Form.ShowDialog as for ApplicationContexts we'll
613                          * fail on nested ShowDialogs, so disable the check for the moment.
614                          */
615                         //if (thread.MessageLoop) {
616                         //        throw new InvalidOperationException ("Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.");
617                         //}
618
619                         msg = new MSG();
620
621                         if (context == null) {
622                                 context = new ApplicationContext();
623                         }
624                 
625                         previous_thread_context = thread.Context;
626                         thread.Context = context;
627
628                         if (context.MainForm != null) {
629                                 context.MainForm.is_modal = Modal;
630                                 context.MainForm.context = context;
631                                 context.MainForm.closing = false;
632                                 context.MainForm.Visible = true;        // Cannot use Show() or scaling gets confused by menus
633                                 // XXX the above line can be used to close the form. another problem with our handling of Show/Activate.
634                                 if (context.MainForm != null)
635                                         context.MainForm.Activate();
636                         }
637
638                         #if DebugRunLoop
639                                 Console.WriteLine("Entering RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
640                         #endif
641
642                         if (Modal) {
643                                 toplevels = new Queue ();
644                                 DisableFormsForModalLoop (toplevels, context);
645                                 
646                                 // FIXME - need activate?
647                                 /* make sure the MainForm is enabled */
648                                 if (context.MainForm != null) {
649                                         XplatUI.EnableWindow (context.MainForm.Handle, true);
650                                         XplatUI.SetModal(context.MainForm.Handle, true);
651                                 }
652                         } else {
653                                 toplevels = null;
654                         }
655
656                         queue_id = XplatUI.StartLoop(Thread.CurrentThread);
657                         thread.MessageLoop = true;
658
659                         bool quit = false;
660
661                         while (!quit && XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0)) {
662                                 lock (message_filters) {
663                                         if (message_filters.Count > 0) {
664                                                 Message m;
665                                                 bool    drop;
666
667                                                 drop = false;
668                                                 m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
669                                                 for (int i = 0; i < message_filters.Count; i++) {
670                                                         if (((IMessageFilter)message_filters[i]).PreFilterMessage(ref m)) {
671                                                                 // we're dropping the message
672                                                                 drop = true;
673                                                                 break;
674                                                         }
675                                                 }
676                                                 if (drop) {
677                                                         continue;
678                                                 }
679                                         }
680                                 }
681
682                                 switch((Msg)msg.message) {
683                                 case Msg.WM_KEYDOWN:
684                                 case Msg.WM_SYSKEYDOWN:
685                                 case Msg.WM_CHAR:
686                                 case Msg.WM_SYSCHAR:
687                                 case Msg.WM_KEYUP:
688                                 case Msg.WM_SYSKEYUP:
689                                         Message m;
690                                         m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
691
692                                         Control c;
693                                         c = Control.FromHandle(msg.hwnd);
694
695 #if NET_2_0
696                                         // If we have a control with keyboard capture (usually a *Strip)
697                                         // give it the message, and then drop the message
698                                         if (keyboard_capture != null) {
699                                                 // WM_SYSKEYUP does not make it into ProcessCmdKey, so do it here
700                                                 if ((Msg)m.Msg == Msg.WM_SYSKEYUP)
701                                                         if (m.WParam.ToInt32() == (int)Keys.Menu) {
702                                                                 keyboard_capture.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.Keyboard);
703                                                                 continue;
704                                                         }
705
706                                                 m.HWnd = keyboard_capture.Handle;
707                                                 
708                                                 if (keyboard_capture.PreProcessControlMessageInternal (ref m) != PreProcessControlState.MessageProcessed && (m.Msg == (int)Msg.WM_KEYDOWN && !keyboard_capture.ProcessControlMnemonic ((char)m.WParam))) {
709                                                         if (c == null || c.Parent == null || !(c.Parent is ToolStrip))
710                                                                 continue;
711                                                         else
712                                                                 m.HWnd = msg.hwnd;
713                                                 } else
714                                                         continue;
715                                         }
716 #endif
717
718                                         if ((c != null) && c.PreProcessControlMessageInternal (ref m) != PreProcessControlState.MessageProcessed) {
719                                                 goto default;
720                                         }
721                                         break;
722 #if NET_2_0
723                                 case Msg.WM_LBUTTONDOWN:
724                                 case Msg.WM_MBUTTONDOWN:
725                                 case Msg.WM_RBUTTONDOWN:
726                                         if (keyboard_capture != null) {
727                                                 Control c2 = Control.FromHandle (msg.hwnd);
728                                                 
729                                                 // If we clicked a ToolStrip, we have to make sure it isn't
730                                                 // the one we are on, or any of its parents or children
731                                                 // If we clicked off the dropped down menu, release everything
732                                                 if (c2 is ToolStrip) {
733                                                         if ((c2 as ToolStrip).GetTopLevelToolStrip () != keyboard_capture.GetTopLevelToolStrip ())
734                                                                 ToolStripManager.FireAppClicked ();
735                                                 } else
736                                                         ToolStripManager.FireAppClicked ();
737                                         }
738                                         
739                                         goto default;
740 #endif
741                                 case Msg.WM_QUIT:
742                                         quit = true; // make sure we exit
743                                         break;
744                                 default:
745                                         XplatUI.TranslateMessage(ref msg);
746                                         XplatUI.DispatchMessage(ref msg);
747                                         break;
748                                 }
749
750                                 // Handle exit, Form might have received WM_CLOSE and set 'closing' in response
751                                 if ((context.MainForm != null) && (context.MainForm.closing || (Modal && !context.MainForm.Visible))) {
752                                         if (!Modal) {
753                                                 XplatUI.PostQuitMessage(0);
754                                         } else {
755                                                 break;
756                                         }
757                                 }
758                         }
759                         #if DebugRunLoop
760                                 Console.WriteLine("   RunLoop loop left");
761                         #endif
762
763                         thread.MessageLoop = false;
764                         XplatUI.EndLoop(Thread.CurrentThread);
765
766                         if (Modal) {
767                                 Form old = context.MainForm;
768
769                                 context.MainForm = null;
770
771                                 EnableFormsForModalLoop (toplevels, context);
772                                 
773                                 if (context.MainForm != null && context.MainForm.IsHandleCreated) {
774                                         XplatUI.SetModal(context.MainForm.Handle, false);
775                                 }
776                                 #if DebugRunLoop
777                                         Console.WriteLine("   Done with the SetModal");
778                                 #endif
779                                 old.RaiseCloseEvents (true);
780                                 old.is_modal = false;
781                         }
782
783                         #if DebugRunLoop
784                                 Console.WriteLine("Leaving RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
785                         #endif
786                         if (context.MainForm != null) {
787                                 context.MainForm.context = null;
788                                 context.MainForm = null;
789                         }
790
791                         thread.Context = previous_thread_context;
792
793                         if (!Modal) {
794                                 thread.Exit();
795                         }
796                 }
797
798                 #endregion      // Public Static Methods
799
800                 #region Events
801                 public static event EventHandler        ApplicationExit;
802
803                 public static event EventHandler        Idle {
804                         add {
805                                 XplatUI.Idle += value;
806                         }
807                         remove {
808                                 XplatUI.Idle -= value;
809                         }
810                 }
811
812                 public static event EventHandler        ThreadExit;
813                 public static event ThreadExceptionEventHandler ThreadException;
814
815 #if NET_2_0
816                 [EditorBrowsable (EditorBrowsableState.Advanced)]
817                 public static event EventHandler EnterThreadModal;
818
819                 [EditorBrowsable (EditorBrowsableState.Advanced)]
820                 public static event EventHandler LeaveThreadModal;
821 #endif
822                 #endregion      // Events
823
824                 #region Public Delegates
825 #if NET_2_0
826                 public delegate bool MessageLoopCallback ();
827 #endif
828                 #endregion
829                 
830                 #region Internal Properties
831 #if NET_2_0
832                 internal static ToolStrip KeyboardCapture {
833                         get { return keyboard_capture; }
834                         set { keyboard_capture = value; }
835                 }
836 #endif
837                 #endregion
838                 
839                 #region Internal Methods
840                 internal static void AddForm (Form f)
841                 {
842                         lock (forms)
843                                 forms.Add (f);
844                 }
845                 
846                 internal static void RemoveForm (Form f)
847                 {
848                         lock (forms)
849                                 forms.Remove (f);
850                 }
851                 #endregion
852         }
853 }