-//\r
-// System.Windows.Forms.Application\r
-//\r
-// Author:\r
-// stubbed out by Jaak Simm (jaaksimm@firm.ee)\r
-// Miguel de Icaza (miguel@ximian.com)\r
-// Dennis hayes (dennish@raytek.com)\r
-// WINELib implementation started by John Sohn (jsohn@columbus.rr.com)\r
-//\r
-// (C) Ximian, Inc 2002\r
-//\r
-\r
-using System;\r
-using System.Drawing;\r
-using Microsoft.Win32;\r
-using System.ComponentModel;\r
-using System.Threading;\r
-using System.Globalization;\r
-using System.Reflection;\r
-using System.Collections;\r
-using System.Runtime.CompilerServices;\r
-\r
-namespace System.Windows.Forms {\r
-\r
- /// <summary>\r
- /// Provides static methods and properties to manage an application, \r
- /// such as methods to start and stop an application, to process \r
- /// Windows messages, and properties to get information about an \r
- /// application. This class cannot be inherited.\r
- /// </summary>\r
-\r
- [MonoTODO]\r
- public sealed class Application {\r
- static private ApplicationContext applicationContext = null;\r
- static private bool messageLoopStarted = false;\r
- static private bool messageLoopStopRequest = false;\r
- private static ArrayList messageFilters = new ArrayList ();\r
-\r
- // --- (public) Properties ---\r
- public static bool AllowQuit {\r
- // according to docs return false if embbedded in a \r
- // browser, not (yet?) embedded in a browser\r
- get { return true; } \r
- }\r
- \r
- [MonoTODO]\r
- public static string CommonAppDataPath {\r
- get { throw new NotImplementedException (); }\r
- }\r
- \r
- [MonoTODO]\r
- // Registry key not yet defined (this should be interesting)\r
- //public static RegistryKey CommonAppDataRegistry {\r
- // get { throw new NotImplementedException (); }\r
- //}\r
- \r
- [MonoTODO]\r
- public static string CompanyName {\r
- get { throw new NotImplementedException (); }\r
- }\r
- \r
- [MonoTODO]\r
- public static CultureInfo CurrentCulture {\r
- get { throw new NotImplementedException (); }\r
- set { throw new NotImplementedException (); }\r
- }\r
- \r
- [MonoTODO]\r
- public static InputLanguage CurrentInputLanguage {\r
- get { throw new NotImplementedException (); }\r
- }\r
- \r
- [MonoTODO]\r
- public static string ExecutablePath {\r
- get { throw new NotImplementedException (); }\r
- }\r
- \r
- [MonoTODO]\r
- public static string LocalUserAppDataPath {\r
- get { throw new NotImplementedException (); }\r
- }\r
- \r
- public static bool MessageLoop {\r
- get { return messageLoopStarted; }\r
- }\r
- \r
- [MonoTODO]\r
- public static string ProductName {\r
- get { throw new NotImplementedException (); }\r
- }\r
- \r
- [MonoTODO]\r
- public static string ProductVersion {\r
- get { throw new NotImplementedException (); }\r
- }\r
- \r
- [MonoTODO]\r
- public static string SafeTopLevelCaptionFormat {\r
- get { throw new NotImplementedException (); }\r
- set { throw new NotImplementedException (); }\r
- }\r
- \r
- [MonoTODO]\r
- public static string StartupPath {\r
- get { throw new NotImplementedException (); }\r
- }\r
- \r
- [MonoTODO]\r
- public static string UserAppDataPath {\r
- get { throw new NotImplementedException (); }\r
- }\r
- \r
- [MonoTODO]\r
- // Registry key not yet defined\r
- //public static RegistryKey UserAppDataRegistry {\r
- // get { throw new NotImplementedException (); }\r
- //}\r
- \r
- // --- Methods ---\r
- public static void AddMessageFilter (IMessageFilter value) \r
- {\r
- messageFilters.Add (value);\r
- }\r
- \r
- public static void DoEvents () \r
- {\r
- Win32.MSG msg = new Win32.MSG();\r
-\r
- while (Win32.PeekMessageA (ref msg, (IntPtr) 0, 0, 0,\r
- Win32.PM_REMOVE) != 0);\r
- }\r
- \r
- public static void Exit () \r
- {\r
- Win32.PostQuitMessage (0);\r
- }\r
- \r
- public static void ExitThread () \r
- {\r
- messageLoopStopRequest = true;\r
- }\r
- \r
- [MonoTODO]\r
- public static ApartmentState OleRequired () \r
- {\r
- throw new NotImplementedException ();\r
- }\r
- \r
- [MonoTODO]\r
- public static void OnThreadException (Exception t) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
- \r
- public static void RemoveMessageFilter (IMessageFilter value)\r
- {\r
- messageFilters.Remove (value);\r
- }\r
-\r
- static private void ApplicationFormClosed (object o, EventArgs args)\r
- {\r
- Win32.PostQuitMessage (0);\r
- }\r
-\r
- static public void Run ()\r
- {\r
- Win32.MSG msg = new Win32.MSG();\r
-\r
- messageLoopStarted = true;\r
-\r
- while (!messageLoopStopRequest && \r
- Win32.GetMessageA (ref msg, 0, 0, 0) != 0) {\r
-\r
- bool dispatchMessage = true;\r
-\r
- Message message = new Message ();\r
- message.HWnd = msg.hwnd;\r
- message.Msg = (int) msg.message;\r
- message.WParam = msg.wParam;\r
- message.LParam = msg.lParam;\r
-\r
- IEnumerator e = messageFilters.GetEnumerator();\r
-\r
- while (e.MoveNext()) {\r
- IMessageFilter filter = \r
- (IMessageFilter) e.Current;\r
-\r
- // if PreFilterMessage returns true\r
- // the message should not be dispatched\r
- if (filter.PreFilterMessage (ref message))\r
- dispatchMessage = false;\r
- }\r
-\r
- if (dispatchMessage) {\r
- Win32.TranslateMessage (ref msg);\r
- Win32.DispatchMessageA (ref msg);\r
- }\r
-\r
- //if (Idle != null)\r
- //Idle (null, new EventArgs());\r
- }\r
-\r
- //if (ApplicationExit != null)\r
- //ApplicationExit (null, new EventArgs());\r
- }\r
-\r
- public static void Run (ApplicationContext context) \r
- {\r
- applicationContext = context;\r
- applicationContext.MainForm.Show ();\r
- applicationContext.MainForm.Closed += \r
- new EventHandler (ApplicationFormClosed);\r
- Run();\r
- }\r
-\r
- //[TypeAttributes.BeforeFieldInit]\r
- public static void Run (Form form)\r
- // Documents say this parameter name should be mainform, \r
- // but the verifier says context.\r
- {\r
- ApplicationContext context = new ApplicationContext (form);\r
- Run (context);\r
- }\r
- \r
- // --- Events ---\r
- public static event EventHandler ApplicationExit;\r
- public static event EventHandler Idle;\r
- public static event ThreadExceptionEventHandler ThreadException;\r
- public static event EventHandler ThreadExit;\r
- }\r
-}\r
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2004 - 2006 Novell, Inc.
+//
+// Authors:
+// Peter Bartok pbartok@novell.com
+// Daniel Nauck (dna(at)mono-project(dot)de)
+//
+
+// COMPLETE
+
+#undef DebugRunLoop
+
+using Microsoft.Win32;
+using System;
+using System.Drawing;
+using System.ComponentModel;
+using System.Collections;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Text;
+using System.Windows.Forms.VisualStyles;
+
+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 readonly Hashtable threads = new Hashtable();
+
+ #endregion // Fields
+
+ #region Constructors
+
+ private MWFThread()
+ {
+ }
+
+ #endregion // Constructors
+
+ #region Properties
+
+ public ApplicationContext Context {
+ get { return context; }
+ set { context = value; }
+ }
+
+ public bool MessageLoop {
+ get { return messageloop_started; }
+ set { messageloop_started = value; }
+ }
+
+ public bool HandlingException {
+ get { return handling_exception; }
+ set { handling_exception = value; }
+ }
+
+ public static int LoopCount {
+ get {
+ lock (threads) {
+ int loops = 0;
+
+ foreach (MWFThread thread in threads.Values) {
+ if (thread.messageloop_started)
+ loops++;
+ }
+
+ return loops;
+ }
+ }
+ }
+
+ public static MWFThread Current {
+ get {
+ MWFThread thread = null;
+
+ lock (threads) {
+ thread = (MWFThread) threads [Thread.CurrentThread.GetHashCode ()];
+ if (thread == null) {
+ thread = new MWFThread();
+ thread.thread_id = Thread.CurrentThread.GetHashCode ();
+ threads [thread.thread_id] = thread;
+ }
+ }
+
+ return thread;
+ }
+ }
+
+ #endregion // Properties
+
+ #region Methods
+
+ public void Exit ()
+ {
+ if (context != null)
+ context.ExitThread();
+ context = null;
+
+ if (Application.ThreadExit != null)
+ Application.ThreadExit(null, EventArgs.Empty);
+
+ if (LoopCount == 0) {
+ if (Application.ApplicationExit != null)
+ Application.ApplicationExit (null, EventArgs.Empty);
+ }
+
+ ((MWFThread) threads [thread_id]).MessageLoop = false;
+ }
+
+ #endregion // Methods
+ }
+
+ 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 ();
+
+ private static bool use_wait_cursor;
+ private static ToolStrip keyboard_capture;
+ private static VisualStyleState visual_style_state = VisualStyleState.ClientAndNonClientAreasEnabled;
+ static bool visual_styles_enabled;
+
+ private Application ()
+ {
+ browser_embedded = false;
+ }
+
+ static Application ()
+ {
+ // Attempt to load UIA support for winforms
+ // UIA support requires .NET 2.0
+ InitializeUIAutomation ();
+ }
+
+ #region Private Methods
+
+ 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
+
+ ArrayList forms_to_close = new ArrayList ();
+
+ lock (forms) {
+ foreach (Form f in forms) {
+ if (thread == null || thread == f.creator_thread)
+ forms_to_close.Add (f);
+ }
+
+ foreach (Form f in forms_to_close) {
+ #if DebugRunLoop
+ Console.WriteLine(" Closing form {0}", f);
+ #endif
+ f.Dispose ();
+ }
+ }
+ }
+
+ #endregion // Private methods
+
+ #region Public Static Properties
+
+ public static bool AllowQuit {
+ get {
+ return !browser_embedded;
+ }
+ }
+
+ public static string CommonAppDataPath {
+ get {
+ return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData));
+ }
+ }
+
+ public static RegistryKey CommonAppDataRegistry {
+ get {
+ string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
+
+ return Registry.LocalMachine.CreateSubKey (key);
+ }
+ }
+
+ public static string CompanyName {
+ get {
+ string company = string.Empty;
+
+ Assembly assembly = Assembly.GetEntryAssembly ();
+
+ 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);
+ }
+ }
+
+ // 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;
+ }
+ }
+
+ public static CultureInfo CurrentCulture {
+ get {
+ return Thread.CurrentThread.CurrentUICulture;
+ }
+ set {
+ Thread.CurrentThread.CurrentUICulture = value;
+ }
+ }
+
+ public static InputLanguage CurrentInputLanguage {
+ get {
+ return input_language;
+ }
+ set {
+ input_language=value;
+ }
+ }
+
+ public static string ExecutablePath {
+ get {
+ return Path.GetFullPath (Environment.GetCommandLineArgs ()[0]);
+ }
+ }
+
+ public static string LocalUserAppDataPath {
+ get {
+ return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData));
+ }
+ }
+
+ public static bool MessageLoop {
+ get {
+ return MWFThread.Current.MessageLoop;
+ }
+ }
+
+ public static string ProductName {
+ get {
+ string name = string.Empty;
+
+ 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);
+ }
+
+ if (name == null || name.Length == 0)
+ name = assembly.EntryPoint.DeclaringType.FullName;
+ }
+
+ return name;
+ }
+ }
+
+ public static string ProductVersion {
+ get {
+ String version = string.Empty;
+
+ 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;
+ }
+ }
+
+ public static string SafeTopLevelCaptionFormat {
+ get {
+ return safe_caption_format;
+ }
+ set {
+ safe_caption_format = value;
+ }
+ }
+
+ public static string StartupPath {
+ get {
+ return Path.GetDirectoryName (Application.ExecutablePath);
+ }
+ }
+
+ public static string UserAppDataPath {
+ get {
+ return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData));
+ }
+ }
+
+ public static RegistryKey UserAppDataRegistry {
+ get {
+ string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
+
+ return Registry.CurrentUser.CreateSubKey (key);
+ }
+ }
+
+ public static bool UseWaitCursor {
+ get {
+ return use_wait_cursor;
+ }
+ set {
+ use_wait_cursor = value;
+ if (use_wait_cursor) {
+ foreach (Form form in OpenForms) {
+ form.Cursor = Cursors.WaitCursor;
+ }
+ }
+ }
+ }
+
+ public static bool RenderWithVisualStyles {
+ 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 false;
+ }
+ }
+
+ public static VisualStyleState VisualStyleState {
+ get { return Application.visual_style_state; }
+ set { Application.visual_style_state = value; }
+ }
+
+ #endregion
+
+ #region Public Static Methods
+
+ public static void AddMessageFilter (IMessageFilter value)
+ {
+ lock (message_filters) {
+ message_filters.Add (value);
+ }
+ }
+
+ internal static void AddKeyFilter (IKeyFilter value)
+ {
+ XplatUI.AddKeyFilter (value);
+ }
+
+ public static void DoEvents ()
+ {
+ XplatUI.DoEvents ();
+ }
+
+ 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
+ //
+ static internal bool use_compatible_text_rendering = true;
+
+ public static void SetCompatibleTextRenderingDefault (bool defaultValue)
+ {
+ use_compatible_text_rendering = defaultValue;
+ }
+
+ public static FormCollection OpenForms {
+ get {
+ 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.
+ //FIXME: SecurityPermission: Restart () requires IsUnrestricted permission.
+
+ if (Assembly.GetEntryAssembly () == null)
+ throw new NotSupportedException ("The method 'Restart' is not supported by this application type.");
+
+ string mono_path = null;
+
+ //Get mono path
+ PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static | BindingFlags.NonPublic);
+ MethodInfo get_gac = null;
+ if (gac != null)
+ get_gac = gac.GetGetMethod (true);
+
+ if (get_gac != null) {
+ string gac_path = Path.GetDirectoryName ((string)get_gac.Invoke (null, null));
+ string mono_prefix = Path.GetDirectoryName (Path.GetDirectoryName (gac_path));
+
+ if (XplatUI.RunningOnUnix) {
+ mono_path = Path.Combine (mono_prefix, "bin/mono");
+ if (!File.Exists (mono_path))
+ mono_path = "mono";
+ } else {
+ mono_path = Path.Combine (mono_prefix, "bin\\mono.bat");
+
+ if (!File.Exists (mono_path))
+ mono_path = Path.Combine (mono_prefix, "bin\\mono.exe");
+
+ if (!File.Exists (mono_path))
+ mono_path = Path.Combine (mono_prefix, "mono\\mono\\mini\\mono.exe");
+
+ if (!File.Exists (mono_path))
+ throw new FileNotFoundException (string.Format ("Windows mono path not found: '{0}'", mono_path));
+ }
+ }
+
+ //Get command line arguments
+ StringBuilder argsBuilder = new StringBuilder ();
+ string[] args = Environment.GetCommandLineArgs ();
+ for (int i = 0; i < args.Length; i++)
+ {
+ argsBuilder.Append (string.Format ("\"{0}\" ", args[i]));
+ }
+ string arguments = argsBuilder.ToString ();
+ ProcessStartInfo procInfo = Process.GetCurrentProcess ().StartInfo;
+
+ if (mono_path == null) { //it is .NET on Windows
+ procInfo.FileName = args[0];
+ procInfo.Arguments = arguments.Remove (0, args[0].Length + 3); //1 space and 2 quotes
+ }
+ else {
+ procInfo.Arguments = arguments;
+ procInfo.FileName = mono_path;
+ }
+
+ procInfo.WorkingDirectory = Environment.CurrentDirectory;
+
+ Application.Exit ();
+ Process.Start (procInfo);
+ }
+
+ public static void Exit ()
+ {
+ Exit (new CancelEventArgs ());
+ }
+
+ [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 ()
+ {
+ //throw new NotImplementedException("OLE Not supported by this System.Windows.Forms implementation");
+ return ApartmentState.Unknown;
+ }
+
+ 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);
+ // 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);
+ }
+
+ try {
+ MWFThread.Current.HandlingException = true;
+
+ 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 ();
+ }
+ } finally {
+ MWFThread.Current.HandlingException = false;
+ }
+ }
+
+ public static void RemoveMessageFilter (IMessageFilter value)
+ {
+ lock (message_filters) {
+ message_filters.Remove (value);
+ }
+ }
+
+ public static void Run ()
+ {
+ Run (new ApplicationContext ());
+ }
+
+ public static void Run (Form mainForm)
+ {
+ Run (new ApplicationContext (mainForm));
+ }
+
+ internal static void FirePreRun ()
+ {
+ EventHandler handler = PreRun;
+ if (handler != null)
+ handler (null, EventArgs.Empty);
+ }
+
+ 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;
+ MSG msg;
+ Object queue_id;
+ MWFThread thread;
+ ApplicationContext previous_thread_context;
+
+ thread = MWFThread.Current;
+
+ /*
+ * There is a NotWorking test for this, but since we are using this method both for Form.ShowDialog as for ApplicationContexts we'll
+ * fail on nested ShowDialogs, so disable the check for the moment.
+ */
+ //if (thread.MessageLoop) {
+ // throw new InvalidOperationException ("Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.");
+ //}
+
+ msg = new MSG();
+
+ if (context == null)
+ context = new ApplicationContext();
+
+ previous_thread_context = thread.Context;
+ thread.Context = context;
+
+ if (context.MainForm != null) {
+ context.MainForm.is_modal = Modal;
+ context.MainForm.context = context;
+ context.MainForm.closing = false;
+ context.MainForm.Visible = true; // Cannot use Show() or scaling gets confused by menus
+ // XXX the above line can be used to close the form. another problem with our handling of Show/Activate.
+ if (context.MainForm != null)
+ context.MainForm.Activate();
+ }
+
+ #if DebugRunLoop
+ Console.WriteLine("Entering RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
+ #endif
+
+ if (Modal) {
+ toplevels = new Queue ();
+ DisableFormsForModalLoop (toplevels, context);
+
+ // FIXME - need activate?
+ /* make sure the MainForm is enabled */
+ if (context.MainForm != null) {
+ XplatUI.EnableWindow (context.MainForm.Handle, true);
+ XplatUI.SetModal(context.MainForm.Handle, true);
+ }
+ } else {
+ toplevels = null;
+ }
+
+ queue_id = XplatUI.StartLoop(Thread.CurrentThread);
+ thread.MessageLoop = true;
+
+ bool quit = false;
+
+ while (!quit && XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0)) {
+ 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:
+ case Msg.WM_CHAR:
+ case Msg.WM_SYSCHAR:
+ case Msg.WM_KEYUP:
+ case Msg.WM_SYSKEYUP:
+ Control c;
+ c = Control.FromHandle(msg.hwnd);
+
+ // 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);
+ break;
+ }
+
+ // 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);
+ } else {
+ break;
+ }
+ }
+ }
+ #if DebugRunLoop
+ Console.WriteLine (" RunLoop loop left");
+ #endif
+
+ thread.MessageLoop = false;
+ XplatUI.EndLoop (Thread.CurrentThread);
+
+ if (Modal) {
+ Form old = context.MainForm;
+
+ context.MainForm = null;
+
+ EnableFormsForModalLoop (toplevels, context);
+
+ if (context.MainForm != null && context.MainForm.IsHandleCreated) {
+ XplatUI.SetModal (context.MainForm.Handle, false);
+ }
+ #if DebugRunLoop
+ Console.WriteLine (" Done with the SetModal");
+ #endif
+ 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");
+ #endif
+
+ if (context.MainForm != null) {
+ context.MainForm.context = null;
+ context.MainForm = null;
+ }
+
+ 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 {
+ add {
+ XplatUI.Idle += value;
+ }
+ remove {
+ XplatUI.Idle -= value;
+ }
+ }
+
+ 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;
+
+#pragma warning disable 0067
+ [MonoTODO]
+ [EditorBrowsable (EditorBrowsableState.Advanced)]
+ public static event EventHandler EnterThreadModal;
+
+ [MonoTODO]
+ [EditorBrowsable (EditorBrowsableState.Advanced)]
+ public static event EventHandler LeaveThreadModal;
+#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)
+ {
+ 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
+ }
+}