Properly update the combo box selected text when the current item is changed, and...
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / Application.cs
index 75414c72f71ca1627aef8610fa9a92827f5a26da..2c2d5bf931d3f08343f4a39947239bc0adacce93 100644 (file)
@@ -39,29 +39,36 @@ using System.IO;
 using System.Reflection;
 using System.Runtime.InteropServices;
 using System.Threading;
-#if NET_2_0
 using System.Text;
 using System.Windows.Forms.VisualStyles;
-#endif
 
-namespace System.Windows.Forms {
-       public sealed class Application {
-               internal class MWFThread {
+namespace System.Windows.Forms
+{
+       public sealed class Application
+       {
+               internal class MWFThread
+               {
                        #region Fields
-                       private ApplicationContext      context;
-                       private bool                    messageloop_started;
-                       private bool                    handling_exception;
-                       private int                     thread_id;
 
-                       private static Hashtable        threads = new Hashtable();
+                       private ApplicationContext context;
+                       private bool messageloop_started;
+                       private bool handling_exception;
+                       private int thread_id;
+
+                       private static readonly Hashtable threads = new Hashtable();
+
                        #endregion      // Fields
 
                        #region Constructors
-                       private MWFThread() {
+
+                       private MWFThread()
+                       {
                        }
+
                        #endregion      // Constructors
 
                        #region Properties
+
                        public ApplicationContext Context {
                                get { return context; }
                                set { context = value; }
@@ -75,7 +82,6 @@ namespace System.Windows.Forms {
                        public bool HandlingException {
                                get { return handling_exception; }
                                set { handling_exception = value; }
-
                        }
 
                        public static int LoopCount {
@@ -95,61 +101,110 @@ namespace System.Windows.Forms {
 
                        public static MWFThread Current {
                                get {
-                                       MWFThread       thread;
+                                       MWFThread thread = null;
 
-                                       thread = null;
                                        lock (threads) {
-                                               thread = (MWFThread)threads[Thread.CurrentThread.GetHashCode()];
+                                               thread = (MWFThread) threads [Thread.CurrentThread.GetHashCode ()];
                                                if (thread == null) {
                                                        thread = new MWFThread();
-                                                       thread.thread_id = Thread.CurrentThread.GetHashCode();
-                                                       threads[thread.thread_id] = thread;
+                                                       thread.thread_id = Thread.CurrentThread.GetHashCode ();
+                                                       threads [thread.thread_id] = thread;
                                                }
                                        }
 
                                        return thread;
                                }
                        }
+
                        #endregion      // Properties
 
                        #region Methods
-                       public void Exit() {
-                               if (context != null) {
+
+                       public void Exit ()
+                       {
+                               if (context != null)
                                        context.ExitThread();
-                               }
                                context = null;
 
-                               if (Application.ThreadExit != null) {
+                               if (Application.ThreadExit != null)
                                        Application.ThreadExit(null, EventArgs.Empty);
-                               }
 
                                if (LoopCount == 0) {
-                                       if (Application.ApplicationExit != null) {
-                                               Application.ApplicationExit(null, EventArgs.Empty);
-                                       }
+                                       if (Application.ApplicationExit != null)
+                                               Application.ApplicationExit (null, EventArgs.Empty);
                                }
 
-                               ((MWFThread)threads[thread_id]).MessageLoop = false;
+                               ((MWFThread) threads [thread_id]).MessageLoop = false;
                        }
+
                        #endregion      // Methods
                }
 
-               private static bool                     browser_embedded        = false;
-               private static InputLanguage            input_language          = InputLanguage.CurrentInputLanguage;
-               private static string                   safe_caption_format     = "{1} - {0} - {2}";
-               private static ArrayList                message_filters         = new ArrayList();
-               private static FormCollection           forms                   = new FormCollection ();
-               private static bool                     use_wait_cursor         = false;
+               private static bool browser_embedded;
+               private static InputLanguage input_language = InputLanguage.CurrentInputLanguage;
+               private static string safe_caption_format = "{1} - {0} - {2}";
+               private static readonly ArrayList message_filters = new ArrayList();
+               private static readonly FormCollection forms = new FormCollection ();
 
-#if NET_2_0
+               private static bool use_wait_cursor;
+               private static ToolStrip keyboard_capture;
                private static VisualStyleState visual_style_state = VisualStyleState.ClientAndNonClientAreasEnabled;
-#endif
+               static bool visual_styles_enabled;
 
-               private Application () {
+               private Application ()
+               {
+                       browser_embedded = false;
+               }
+
+               static Application ()
+               {
+                       // Attempt to load UIA support for winforms
+                       // UIA support requires .NET 2.0
+                       InitializeUIAutomation ();
                }
 
                #region Private Methods
-               internal static void CloseForms(Thread thread) {
+
+               private static void InitializeUIAutomation ()
+               {
+                       // Initialize the UIAutomationWinforms Global class,
+                       // which create some listeners which subscribe to internal
+                       // MWF events so that it can provide a11y support for MWF
+                       const string UIA_WINFORMS_ASSEMBLY = 
+                         "UIAutomationWinforms, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f4ceacb585d99812";
+                       MethodInfo init_method;
+                       Assembly mwf_providers = null;
+                       try {
+                               mwf_providers = Assembly.Load (UIA_WINFORMS_ASSEMBLY);
+                       } catch { }
+                       
+                       if (mwf_providers == null)
+                               return;
+
+                       const string UIA_WINFORMS_TYPE     = "Mono.UIAutomation.Winforms.Global";
+                       const string UIA_WINFORMS_METHOD   = "Initialize";
+                       try {
+                               Type global_type = mwf_providers.GetType (UIA_WINFORMS_TYPE, false);
+                               if (global_type != null) {
+                                       init_method = global_type.GetMethod (UIA_WINFORMS_METHOD, 
+                                                                            BindingFlags.Static | 
+                                                                            BindingFlags.Public);
+                                       if (init_method != null)
+                                               init_method.Invoke (null, new object [] {});
+                                       else
+                                               throw new Exception (String.Format ("Method {0} not found in type {1}.",
+                                                                                   UIA_WINFORMS_METHOD, UIA_WINFORMS_TYPE));
+                               }
+                               else
+                                       throw new Exception (String.Format ("Type {0} not found in assembly {1}.",
+                                                                           UIA_WINFORMS_TYPE, UIA_WINFORMS_ASSEMBLY));
+                       } catch (Exception ex) {
+                               Console.Error.WriteLine ("Error setting up UIA: " + ex);
+                       }
+               }
+               
+               internal static void CloseForms (Thread thread)
+               {
                        #if DebugRunLoop
                                Console.WriteLine("   CloseForms({0}) called", thread);
                        #endif
@@ -170,9 +225,11 @@ namespace System.Windows.Forms {
                                }
                        }
                }
+
                #endregion      // Private methods
 
                #region Public Static Properties
+
                public static bool AllowQuit {
                        get {
                                return !browser_embedded;
@@ -181,29 +238,51 @@ namespace System.Windows.Forms {
 
                public static string CommonAppDataPath {
                        get {
-                               return Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
+                               return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData));
                        }
                }
 
                public static RegistryKey CommonAppDataRegistry {
                        get {
-                               RegistryKey     key;
-
-                               key = Registry.LocalMachine.OpenSubKey("Software\\" + Application.CompanyName + "\\" + Application.ProductName + "\\" + Application.ProductVersion, true);
+                               string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
 
-                               return key;
+                               return Registry.LocalMachine.CreateSubKey (key);
                        }
                }
 
                public static string CompanyName {
                        get {
-                               AssemblyCompanyAttribute[] attrs = (AssemblyCompanyAttribute[]) Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), true);
+                               string company = string.Empty;
+
+                               Assembly assembly = Assembly.GetEntryAssembly ();
                                
-                               if ((attrs != null) && attrs.Length>0) {
-                                       return attrs[0].Company;
-                               }
+                               if (assembly == null)
+                                       assembly = Assembly.GetCallingAssembly ();
+
+                               AssemblyCompanyAttribute[] attrs = (AssemblyCompanyAttribute[])
+                                       assembly.GetCustomAttributes (typeof(AssemblyCompanyAttribute), true);
+                               if (attrs != null && attrs.Length > 0)
+                                       company = attrs [0].Company;
+
+                               // If there is no [AssemblyCompany], return the outermost namespace
+                               // on Main ()
+                               if (company == null || company.Length == 0)
+                                       if (assembly.EntryPoint != null) {
+                                               company = assembly.EntryPoint.DeclaringType.Namespace;
+
+                                               if (company != null) {
+                                                       int firstDot = company.IndexOf ('.');
+                                                       if (firstDot >= 0)
+                                                               company = company.Substring (0, firstDot);
+                                               }
+                                       }
 
-                               return Assembly.GetEntryAssembly().GetName().Name;
+                               // If that doesn't work, return the name of class containing Main ()
+                               if (company == null || company.Length == 0)
+                                       if (assembly.EntryPoint != null)
+                                               company = assembly.EntryPoint.DeclaringType.FullName;
+                               
+                               return company;
                        }
                }
 
@@ -211,10 +290,8 @@ namespace System.Windows.Forms {
                        get {
                                return Thread.CurrentThread.CurrentUICulture;
                        }
-
                        set {
-                               
-                               Thread.CurrentThread.CurrentUICulture=value;
+                               Thread.CurrentThread.CurrentUICulture = value;
                        }
                }
 
@@ -222,7 +299,6 @@ namespace System.Windows.Forms {
                        get {
                                return input_language;
                        }
-
                        set {
                                input_language=value;
                        }
@@ -230,13 +306,13 @@ namespace System.Windows.Forms {
 
                public static string ExecutablePath {
                        get {
-                               return Assembly.GetEntryAssembly().Location;
+                               return Path.GetFullPath (Environment.GetCommandLineArgs ()[0]);
                        }
                }
 
                public static string LocalUserAppDataPath {
                        get {
-                               return Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), CompanyName), ProductName), ProductVersion);
+                               return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData));
                        }
                }
 
@@ -248,21 +324,73 @@ namespace System.Windows.Forms {
 
                public static string ProductName {
                        get {
-                               AssemblyProductAttribute[] attrs = (AssemblyProductAttribute[]) Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true);
+                               string name = string.Empty;
                                
-                               if ((attrs != null) && attrs.Length>0) {
-                                       return attrs[0].Product;
-                               }
+                               Assembly assembly = Assembly.GetEntryAssembly ();
+                               
+                               if (assembly == null)
+                                       assembly = Assembly.GetCallingAssembly ();
+
+                               AssemblyProductAttribute[] attrs = (AssemblyProductAttribute[])
+                                       assembly.GetCustomAttributes (typeof(AssemblyProductAttribute), true);
+
+                               if (attrs != null && attrs.Length > 0)
+                                       name = attrs [0].Product;
+
+                               // If there is no [AssemblyProduct], .NET returns the name of 
+                               // the innermost namespace and if that fails, resorts to the 
+                               // name of the class containing Main ()
+                               if (name == null || name.Length == 0)
+                                       if (assembly.EntryPoint != null) {
+                                               name = assembly.EntryPoint.DeclaringType.Namespace;
+
+                                               if (name != null) {
+                                                       int lastDot = name.LastIndexOf ('.');
+                                                       if (lastDot >= 0 && lastDot < name.Length - 1)
+                                                               name = name.Substring (lastDot + 1);
+                                               }
 
-                               return Assembly.GetEntryAssembly().GetName().Name;
+                                               if (name == null || name.Length == 0)
+                                                       name = assembly.EntryPoint.DeclaringType.FullName;
+                                       }
+
+                               return name;
                        }
                }
 
                public static string ProductVersion {
                        get {
-                               String version;
+                               String version = string.Empty;
 
-                               version = Assembly.GetEntryAssembly().GetName().Version.ToString();
+                               Assembly assembly = Assembly.GetEntryAssembly ();
+                               
+                               if (assembly == null)
+                                       assembly = Assembly.GetCallingAssembly ();
+
+                               AssemblyInformationalVersionAttribute infoVersion =
+                                       Attribute.GetCustomAttribute (assembly,
+                                       typeof (AssemblyInformationalVersionAttribute))
+                                       as AssemblyInformationalVersionAttribute;
+                                       
+                               if (infoVersion != null)
+                                       version = infoVersion.InformationalVersion;
+
+                               // If [AssemblyFileVersion] is present it is used
+                               // before resorting to assembly version
+                               if (version == null || version.Length == 0) {
+                                       AssemblyFileVersionAttribute fileVersion =
+                                               Attribute.GetCustomAttribute (assembly,
+                                               typeof (AssemblyFileVersionAttribute))
+                                               as AssemblyFileVersionAttribute;
+                                       if (fileVersion != null)
+                                               version = fileVersion.Version;
+                               }
+
+                               // If neither [AssemblyInformationalVersionAttribute]
+                               // nor [AssemblyFileVersion] are present, then use
+                               // the assembly version
+                               if (version == null || version.Length == 0)
+                                       version = assembly.GetName ().Version.ToString ();
 
                                return version;
                        }
@@ -272,36 +400,31 @@ namespace System.Windows.Forms {
                        get {
                                return safe_caption_format;
                        }
-
                        set {
-                               safe_caption_format=value;
+                               safe_caption_format = value;
                        }
                }
 
                public static string StartupPath {
                        get {
-                               return Path.GetDirectoryName(Application.ExecutablePath);
+                               return Path.GetDirectoryName (Application.ExecutablePath);
                        }
                }
 
                public static string UserAppDataPath {
                        get {
-                               return Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), CompanyName), ProductName), ProductVersion);
+                               return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData));
                        }
                }
 
                public static RegistryKey UserAppDataRegistry {
                        get {
-                               RegistryKey     key;
-
-                               key = Registry.CurrentUser.OpenSubKey("Software\\" + Application.CompanyName + "\\" + Application.ProductName + "\\" + Application.ProductVersion, true);
-
-                               return key;
+                               string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
+                               
+                               return Registry.CurrentUser.CreateSubKey (key);
                        }
                }
 
-#if NET_2_0
-
                public static bool UseWaitCursor {
                        get {
                                return use_wait_cursor;
@@ -315,52 +438,68 @@ namespace System.Windows.Forms {
                                }
                        }
                }
-               
+
                public static bool RenderWithVisualStyles {
-                     get {
-                               if (VisualStyleInformation.IsSupportedByOS)
-                               {
+                       get {
+                               if (VisualStyleInformation.IsSupportedByOS) {
                                        if (!VisualStyleInformation.IsEnabledByUser)
                                                return false;
-                                 
                                        if (!XplatUI.ThemesEnabled)
                                                return false;
-                                 
                                        if (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled)
                                                return true;
-                                 
                                        if (Application.VisualStyleState == VisualStyleState.ClientAreaEnabled)
-                                               return true;
+                                               return true;
                                }
-                               
                                return false;
-                     }
+                       }
                }
 
                public static VisualStyleState VisualStyleState {
                        get { return Application.visual_style_state; }
                        set { Application.visual_style_state = value; }
                }
-#endif
 
                #endregion
 
                #region Public Static Methods
-               public static void AddMessageFilter(IMessageFilter value) {
+
+               public static void AddMessageFilter (IMessageFilter value)
+               {
                        lock (message_filters) {
-                               message_filters.Add(value);
+                               message_filters.Add (value);
                        }
                }
 
-               public static void DoEvents() {
-                       XplatUI.DoEvents();
+               internal static void AddKeyFilter (IKeyFilter value)
+               {
+                       XplatUI.AddKeyFilter (value);
                }
 
-               public static void EnableVisualStyles() {
-                       XplatUI.EnableThemes();
+               public static void DoEvents ()
+               {
+                       XplatUI.DoEvents ();
                }
 
-#if NET_2_0
+               public static void EnableVisualStyles ()
+               {
+                       visual_styles_enabled = true;
+                       XplatUI.EnableThemes ();
+               }
+
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+               public static bool FilterMessage (ref Message message)
+               {
+                       lock (message_filters) {
+                               for (int i = 0; i < message_filters.Count; i++) {
+                                       IMessageFilter filter = (IMessageFilter) message_filters[i];
+                                       if (filter.PreFilterMessage (ref message))
+                                               return true;
+                               }
+                       }
+                       return false;
+               }
+               
                //
                // If true, it uses GDI+, performance reasons were quoted
                //
@@ -376,7 +515,43 @@ namespace System.Windows.Forms {
                                return forms;
                        }
                }
+               
+               [MonoNotSupported ("Only applies when Winforms is being hosted by an unmanaged app.")]
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+               public static void RegisterMessageLoop (MessageLoopCallback callback)
+               {
+               }
 
+               [MonoNotSupported ("Empty stub.")]
+               public static bool SetSuspendState (PowerState state, bool force, bool disableWakeEvent)
+               {
+                       return false;
+               }
+
+               [MonoNotSupported ("Empty stub.")]
+               public static void SetUnhandledExceptionMode (UnhandledExceptionMode mode)
+               {
+                       //FIXME: a stub to fill
+               }
+
+               [MonoNotSupported ("Empty stub.")]
+               public static void SetUnhandledExceptionMode (UnhandledExceptionMode mode, bool threadScope)
+               {
+                       //FIXME: a stub to fill
+               }
+
+               [MonoNotSupported ("Only applies when Winforms is being hosted by an unmanaged app.")]
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+               public static void UnregisterMessageLoop ()
+               {
+               }
+
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+               public static void RaiseIdle (EventArgs e)
+               {
+                       XplatUI.RaiseIdle (e);
+               }
+               
                public static void Restart ()
                {
                        //FIXME: ClickOnce stuff using the Update or UpdateAsync methods.
@@ -397,12 +572,11 @@ namespace System.Windows.Forms {
                                string gac_path = Path.GetDirectoryName ((string)get_gac.Invoke (null, null));
                                string mono_prefix = Path.GetDirectoryName (Path.GetDirectoryName (gac_path));
 
-                               if (Environment.OSVersion.Platform == PlatformID.Unix) {
+                               if (XplatUI.RunningOnUnix) {
                                        mono_path = Path.Combine (mono_prefix, "bin/mono");
                                        if (!File.Exists (mono_path))
                                                mono_path = "mono";
-                               }
-                               else {
+                               } else {
                                        mono_path = Path.Combine (mono_prefix, "bin\\mono.bat");
 
                                        if (!File.Exists (mono_path))
@@ -440,76 +614,190 @@ namespace System.Windows.Forms {
                        Application.Exit ();
                        Process.Start (procInfo);
                }
-#endif
 
-               public static void Exit() {
-                       XplatUI.PostQuitMessage(0);
-                       CloseForms(null);
+               public static void Exit ()
+               {
+                       Exit (new CancelEventArgs ());
                }
 
-               public static void ExitThread() {
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+               public static void Exit (CancelEventArgs e)
+               {
+                       ArrayList forms_to_close;
+                       
+                       lock (forms) {
+                               forms_to_close = new ArrayList (forms);
+
+                               foreach (Form f in forms_to_close) {
+                                       // Give each form a chance to cancel the Application.Exit
+                                       e.Cancel = f.FireClosingEvents (CloseReason.ApplicationExitCall, false);
+
+                                       if (e.Cancel)
+                                               return;
+
+                                       f.suppress_closing_events = true;
+                                       f.Close ();
+                                       f.Dispose ();
+                               }
+                       }
+
+                       XplatUI.PostQuitMessage (0);
+               }
+
+               public static void ExitThread()
+               {
                        CloseForms(Thread.CurrentThread);
                        // this might not be right - need to investigate (somehow) if a WM_QUIT message is generated here
                        XplatUI.PostQuitMessage(0);
                }
 
-               public static ApartmentState OleRequired() {
+               public static ApartmentState OleRequired ()
+               {
                        //throw new NotImplementedException("OLE Not supported by this System.Windows.Forms implementation");
                        return ApartmentState.Unknown;
                }
 
-               public static void OnThreadException(Exception t) {
+               public static void OnThreadException (Exception t)
+               {
                        if (MWFThread.Current.HandlingException) {
                                /* we're already handling an exception and we got
                                   another one?  print it out and exit, this means
                                   we've got a runtime/SWF bug. */
                                Console.WriteLine (t);
-                               Application.Exit();
+                               // Don't use Application.Exit here, since it may cause a stack overflow
+                               // in certain cases. It's however hard to reproduce since it seems to 
+                               // be depending on when the GC kicks in.
+                               Environment.Exit(1);
                        }
 
-                       MWFThread.Current.HandlingException = true;
+                       try {
+                               MWFThread.Current.HandlingException = true;
 
-                       if (Application.ThreadException != null) {
-                               Application.ThreadException(null, new ThreadExceptionEventArgs(t));
-                               return;
-                       }
+                               if (Application.ThreadException != null) {
+                                       Application.ThreadException(null, new ThreadExceptionEventArgs(t));
+                                       return;
+                               }
 
-                       if (SystemInformation.UserInteractive) {
-                               Form form = new ThreadExceptionDialog (t);
-                               form.ShowDialog ();
-                       } else {
-                               Console.WriteLine (t.ToString ());
-                               Application.Exit ();
+                               if (SystemInformation.UserInteractive) {
+                                       Form form = new ThreadExceptionDialog (t);
+                                       form.ShowDialog ();
+                               } else {
+                                       Console.WriteLine (t.ToString ());
+                                       Application.Exit ();
+                               }
+                       } finally {
+                               MWFThread.Current.HandlingException = false;
                        }
-
-                       MWFThread.Current.HandlingException = false;
                }
 
-               public static void RemoveMessageFilter(IMessageFilter filter) {
+               public static void RemoveMessageFilter (IMessageFilter value)
+               {
                        lock (message_filters) {
-                               message_filters.Remove(filter);
+                               message_filters.Remove (value);
                        }
                }
 
-               public static void Run() {
-                       RunLoop(false, new ApplicationContext());
+               public static void Run ()
+               {
+                       Run (new ApplicationContext ());
                }
 
-               public static void Run(Form mainForm) {
-                       RunLoop(false, new ApplicationContext(mainForm));
+               public static void Run (Form mainForm)
+               {
+                       Run (new ApplicationContext (mainForm));
                }
 
-               public static void Run(ApplicationContext context) {
-                       RunLoop(false, context);
+               internal static void FirePreRun ()
+               {
+                       EventHandler handler = PreRun;
+                       if (handler != null)
+                               handler (null, EventArgs.Empty);
                }
 
-               internal static void RunLoop(bool Modal, ApplicationContext context) {
+               public static void Run (ApplicationContext context)
+               {
+                       // If a sync context hasn't been created by now, create
+                       // a default one
+                       if (SynchronizationContext.Current == null)
+                               SynchronizationContext.SetSynchronizationContext (new SynchronizationContext ());
+                               
+                       RunLoop (false, context);
+                       
+                       // Reset the sync context back to the default
+                       if (SynchronizationContext.Current is WindowsFormsSynchronizationContext)
+                               WindowsFormsSynchronizationContext.Uninstall ();
+               }
+
+               private static void DisableFormsForModalLoop (Queue toplevels, ApplicationContext context)
+               {
+                       Form f;
+
+                       lock (forms) {
+                               IEnumerator control = forms.GetEnumerator ();
+
+                               while (control.MoveNext ()) {
+                                       f = (Form)control.Current;
+
+                                       // Don't disable the main form.
+                                       if (f == context.MainForm) {
+                                               continue;
+                                       }
+
+                                       // Don't disable any children of the main form.
+                                       // These do not have to be MDI children.
+                                       Control current = f;
+                                       bool is_child_of_main = false; ;
+
+                                       do {
+                                               if (current.Parent == context.MainForm) {
+                                                       is_child_of_main = true;
+                                                       break;
+                                               }
+                                               current = current.Parent;
+                                       } while (current != null);
+
+                                       if (is_child_of_main)
+                                               continue;
+
+                                       // Disable the rest
+                                       if (f.IsHandleCreated && XplatUI.IsEnabled (f.Handle)) {
+#if DebugRunLoop
+                                               Console.WriteLine("      Disabling form {0}", f);
+#endif
+                                               XplatUI.EnableWindow (f.Handle, false);
+                                               toplevels.Enqueue (f);
+                                       }
+                               }
+                       }
+                               
+               }
+               
+               
+               private static void EnableFormsForModalLoop (Queue toplevels, ApplicationContext context)
+               {
+                       while (toplevels.Count > 0) {
+#if DebugRunLoop
+                               Console.WriteLine("      Re-Enabling form form {0}", toplevels.Peek());
+#endif
+                               Form c = (Form) toplevels.Dequeue ();
+                               if (c.IsHandleCreated) {
+                                       XplatUI.EnableWindow (c.window.Handle, true);
+                                       context.MainForm = c;
+                               }
+                       }
+#if DebugRunLoop
+                       Console.WriteLine("   Done with the re-enable");
+#endif
+               }
+
+               internal static void RunLoop (bool Modal, ApplicationContext context)
+               {
                        Queue           toplevels;
-                       IEnumerator     control;
                        MSG             msg;
                        Object          queue_id;
                        MWFThread       thread;
-
+                       ApplicationContext previous_thread_context;
+                       
                        thread = MWFThread.Current;
 
                        /*
@@ -522,10 +810,10 @@ namespace System.Windows.Forms {
 
                        msg = new MSG();
 
-                       if (context == null) {
+                       if (context == null)
                                context = new ApplicationContext();
-                       }
-
+               
+                       previous_thread_context = thread.Context;
                        thread.Context = context;
 
                        if (context.MainForm != null) {
@@ -543,47 +831,8 @@ namespace System.Windows.Forms {
                        #endif
 
                        if (Modal) {
-                               Form f;
-
-                               toplevels = new Queue();
-                               
-                               lock (forms) {
-                                       control = forms.GetEnumerator();
-
-                                       while (control.MoveNext()) {
-                                               f = (Form)control.Current;
-                                               
-                                               // Don't disable the main form.
-                                               if (f == context.MainForm) {
-                                                       continue;
-                                               }
-                                               
-                                               // Don't disable any children of the main form.
-                                               // These do not have to be MDI children.
-                                               Control current = f;
-                                               bool is_child_of_main = false;;
-
-                                               do {
-                                                       if (current.Parent == context.MainForm) {
-                                                               is_child_of_main = true;
-                                                               break;
-                                                       }
-                                                       current = current.Parent;
-                                               } while (current != null);
-
-                                               if (is_child_of_main)
-                                                       continue;
-                                               
-                                               // Disable the rest
-                                               if (f.IsHandleCreated && XplatUI.IsEnabled(f.Handle)) {
-                                                       #if DebugRunLoop
-                                                               Console.WriteLine("      Disabling form {0}", f);
-                                                       #endif
-                                                       XplatUI.EnableWindow(f.Handle, false);
-                                                       toplevels.Enqueue(f);
-                                               }
-                                       }
-                               }
+                               toplevels = new Queue ();
+                               DisableFormsForModalLoop (toplevels, context);
                                
                                // FIXME - need activate?
                                /* make sure the MainForm is enabled */
@@ -601,26 +850,11 @@ namespace System.Windows.Forms {
                        bool quit = false;
 
                        while (!quit && XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0)) {
-                               lock (message_filters) {
-                                       if (message_filters.Count > 0) {
-                                               Message m;
-                                               bool    drop;
-
-                                               drop = false;
-                                               m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
-                                               for (int i = 0; i < message_filters.Count; i++) {
-                                                       if (((IMessageFilter)message_filters[i]).PreFilterMessage(ref m)) {
-                                                               // we're dropping the message
-                                                               drop = true;
-                                                               break;
-                                                       }
-                                               }
-                                               if (drop) {
-                                                       continue;
-                                               }
-                                       }
-                               }
-
+                               Message m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
+                               
+                               if (Application.FilterMessage (ref m))
+                                       continue;
+                                       
                                switch((Msg)msg.message) {
                                case Msg.WM_KEYDOWN:
                                case Msg.WM_SYSKEYDOWN:
@@ -628,89 +862,145 @@ namespace System.Windows.Forms {
                                case Msg.WM_SYSCHAR:
                                case Msg.WM_KEYUP:
                                case Msg.WM_SYSKEYUP:
-                                       Message m;
                                        Control c;
-
-                                       m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
                                        c = Control.FromHandle(msg.hwnd);
-                                       if ((c != null) && !c.PreProcessMessage(ref m)) {
-                                               goto default;
+
+                                       // If we have a control with keyboard capture (usually a *Strip)
+                                       // give it the message, and then drop the message
+                                       if (keyboard_capture != null) {
+                                               // WM_SYSKEYUP does not make it into ProcessCmdKey, so do it here
+                                               if ((Msg)m.Msg == Msg.WM_SYSKEYDOWN)
+                                                       if (m.WParam.ToInt32() == (int)Keys.Menu) {
+                                                               keyboard_capture.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.Keyboard);
+                                                               continue;
+                                                       }
+
+                                               m.HWnd = keyboard_capture.Handle;
+
+                                               switch (keyboard_capture.PreProcessControlMessageInternal (ref m)) {
+                                                       case PreProcessControlState.MessageProcessed:
+                                                               continue;
+                                                       case PreProcessControlState.MessageNeeded:
+                                                       case PreProcessControlState.MessageNotNeeded:
+                                                               if (((m.Msg == (int)Msg.WM_KEYDOWN || m.Msg == (int)Msg.WM_CHAR) && !keyboard_capture.ProcessControlMnemonic ((char)m.WParam))) {
+                                                                       if (c == null || !ControlOnToolStrip (c))
+                                                                               continue;
+                                                                       else
+                                                                               m.HWnd = msg.hwnd;
+                                                               } else
+                                                                       continue;
+                                                               
+                                                               break;
+                                               }
                                        }
+
+                                       if (((c != null) && c.PreProcessControlMessageInternal (ref m) != PreProcessControlState.MessageProcessed) ||
+                                               (c == null)) {
+                                               goto default;
+                                       } 
                                        break;
+
+                               case Msg.WM_LBUTTONDOWN:
+                               case Msg.WM_MBUTTONDOWN:
+                               case Msg.WM_RBUTTONDOWN:
+                                       if (keyboard_capture != null) {
+                                               Control c2 = Control.FromHandle (msg.hwnd);
+
+                                               // the target is not a winforms control (an embedded control, perhaps), so
+                                               // release everything
+                                               if (c2 == null) {
+                                                       ToolStripManager.FireAppClicked ();
+                                                       goto default;
+                                               }
+
+                                               // If we clicked a ToolStrip, we have to make sure it isn't
+                                               // the one we are on, or any of its parents or children
+                                               // If we clicked off the dropped down menu, release everything
+                                               if (c2 is ToolStrip) {
+                                                       if ((c2 as ToolStrip).GetTopLevelToolStrip () != keyboard_capture.GetTopLevelToolStrip ())
+                                                               ToolStripManager.FireAppClicked ();
+                                               } else {
+                                                       if (c2.Parent != null)
+                                                               if (c2.Parent is ToolStripDropDownMenu)
+                                                                       if ((c2.Parent as ToolStripDropDownMenu).GetTopLevelToolStrip () == keyboard_capture.GetTopLevelToolStrip ())
+                                                                               goto default;
+                                                       if (c2.TopLevelControl == null)
+                                                               goto default;
+                                                               
+                                                       ToolStripManager.FireAppClicked ();
+                                               }
+                                       }
+                                       
+                                       goto default;
+
                                case Msg.WM_QUIT:
                                        quit = true; // make sure we exit
                                        break;
                                default:
-                                       XplatUI.TranslateMessage(ref msg);
-                                       XplatUI.DispatchMessage(ref msg);
+                                       XplatUI.TranslateMessage (ref msg);
+                                       XplatUI.DispatchMessage (ref msg);
                                        break;
                                }
 
-                               // Handle exit, Form might have received WM_CLOSE and set 'closing' in response
+                               // If our Form doesn't have a handle anymore, it means it was destroyed and we need to *wait* for WM_QUIT.
+                               if ((context.MainForm != null) && (!context.MainForm.IsHandleCreated))
+                                       continue;
+
+                               // Handle exit, Form might have received WM_CLOSE and set 'closing' in response.
                                if ((context.MainForm != null) && (context.MainForm.closing || (Modal && !context.MainForm.Visible))) {
                                        if (!Modal) {
-                                               XplatUI.PostQuitMessage(0);
+                                               XplatUI.PostQuitMessage (0);
                                        } else {
                                                break;
                                        }
                                }
                        }
                        #if DebugRunLoop
-                               Console.WriteLine("   RunLoop loop left");
+                               Console.WriteLine ("   RunLoop loop left");
                        #endif
 
                        thread.MessageLoop = false;
-                       XplatUI.EndLoop(Thread.CurrentThread);
+                       XplatUI.EndLoop (Thread.CurrentThread);
 
                        if (Modal) {
-                               Form c;
-
                                Form old = context.MainForm;
 
                                context.MainForm = null;
 
-                               while (toplevels.Count>0) {
-                                       #if DebugRunLoop
-                                               Console.WriteLine("      Re-Enabling form form {0}", toplevels.Peek());
-                                       #endif
-                                       c = (Form)toplevels.Dequeue();
-                                       if (c.IsHandleCreated) {
-                                               XplatUI.EnableWindow(c.window.Handle, true);
-                                               context.MainForm = c;
-                                       }
-                               }
-                               #if DebugRunLoop
-                                       Console.WriteLine("   Done with the re-enable");
-                               #endif
+                               EnableFormsForModalLoop (toplevels, context);
+                               
                                if (context.MainForm != null && context.MainForm.IsHandleCreated) {
-                                       XplatUI.SetModal(context.MainForm.Handle, false);
+                                       XplatUI.SetModal (context.MainForm.Handle, false);
                                }
                                #if DebugRunLoop
-                                       Console.WriteLine("   Done with the SetModal");
+                                       Console.WriteLine ("   Done with the SetModal");
                                #endif
-                               old.Close();
+                               old.RaiseCloseEvents (true, false);
                                old.is_modal = false;
                        }
 
                        #if DebugRunLoop
-                               Console.WriteLine("Leaving RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
+                               Console.WriteLine ("Leaving RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
                        #endif
+
                        if (context.MainForm != null) {
                                context.MainForm.context = null;
                                context.MainForm = null;
                        }
 
-                       if (!Modal) {
+                       thread.Context = previous_thread_context;
+
+                       if (!Modal)
                                thread.Exit();
-                       }
                }
 
                #endregion      // Public Static Methods
 
                #region Events
-               public static event EventHandler        ApplicationExit;
 
-               public static event EventHandler        Idle {
+               public static event EventHandler ApplicationExit;
+
+               public static event EventHandler Idle {
                        add {
                                XplatUI.Idle += value;
                        }
@@ -719,23 +1009,56 @@ namespace System.Windows.Forms {
                        }
                }
 
-               public static event EventHandler        ThreadExit;
-               public static event ThreadExceptionEventHandler ThreadException;
+               public static event EventHandler ThreadExit;
+               public static event ThreadExceptionEventHandler ThreadException;
+               
+               // These are used externally by the UIA framework
+               internal static event EventHandler FormAdded;
+               internal static event EventHandler PreRun;
 
-#if NET_2_0
+#pragma warning disable 0067
+               [MonoTODO]
                [EditorBrowsable (EditorBrowsableState.Advanced)]
                public static event EventHandler EnterThreadModal;
 
+               [MonoTODO]
                [EditorBrowsable (EditorBrowsableState.Advanced)]
                public static event EventHandler LeaveThreadModal;
-#endif
+#pragma warning restore 0067
+
                #endregion      // Events
 
+               #region Public Delegates
+
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+               public delegate bool MessageLoopCallback ();
+
+               #endregion
+               
+               #region Internal Properties
+               internal static ToolStrip KeyboardCapture {
+                       get { return keyboard_capture; }
+                       set { keyboard_capture = value; }
+               }
+
+               internal static bool VisualStylesEnabled {
+                       get { return visual_styles_enabled; }
+               }
+               #endregion
+               
                #region Internal Methods
+
                internal static void AddForm (Form f)
                {
                        lock (forms)
                                forms.Add (f);
+                       // Signal that a Form has been added to this
+                       // Application. Used by UIA to detect new Forms that
+                       // need a11y support. This event may be fired even if
+                       // the form has already been added, so clients should
+                       // account for that when handling this signal.
+                       if (FormAdded != null)
+                               FormAdded (f, null);
                }
                
                internal static void RemoveForm (Form f)
@@ -743,6 +1066,36 @@ namespace System.Windows.Forms {
                        lock (forms)
                                forms.Remove (f);
                }
+
+               private static bool ControlOnToolStrip (Control c)
+               {
+                       Control p = c.Parent;
+                       
+                       while (p != null) {
+                               if (p is ToolStrip)
+                                       return true;
+                                       
+                               p = p.Parent;
+                       }
+                       
+                       return false;
+               }
+
+               // Takes a starting path, appends company name, product name, and
+               // product version.  If the directory doesn't exist, create it
+               private static string CreateDataPath (string basePath)
+               {
+                       string path;
+
+                       path = Path.Combine (basePath, CompanyName);
+                       path = Path.Combine (path, ProductName);
+                       path = Path.Combine (path, ProductVersion);
+
+                       if (!Directory.Exists (path))
+                               Directory.CreateDirectory (path);
+                       
+                       return path;
+               }
                #endregion
        }
 }