1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004 - 2006 Novell, Inc.
23 // Peter Bartok pbartok@novell.com
24 // Daniel Nauck (dna(at)mono-project(dot)de)
31 using Microsoft.Win32;
34 using System.ComponentModel;
35 using System.Collections;
36 using System.Diagnostics;
37 using System.Globalization;
39 using System.Reflection;
40 using System.Runtime.InteropServices;
41 using System.Threading;
45 using System.Windows.Forms.VisualStyles;
47 namespace System.Windows.Forms
49 public sealed class Application
51 internal class MWFThread
55 private ApplicationContext context;
56 private bool messageloop_started;
57 private bool handling_exception;
58 private int thread_id;
60 private static readonly Hashtable threads = new Hashtable();
70 #endregion // Constructors
74 public ApplicationContext Context {
75 get { return context; }
76 set { context = value; }
79 public bool MessageLoop {
80 get { return messageloop_started; }
81 set { messageloop_started = value; }
84 public bool HandlingException {
85 get { return handling_exception; }
86 set { handling_exception = value; }
89 public static int LoopCount {
94 foreach (MWFThread thread in threads.Values) {
95 if (thread.messageloop_started)
104 public static MWFThread Current {
106 MWFThread thread = null;
109 thread = (MWFThread) threads [Thread.CurrentThread.GetHashCode ()];
110 if (thread == null) {
111 thread = new MWFThread();
112 thread.thread_id = Thread.CurrentThread.GetHashCode ();
113 threads [thread.thread_id] = thread;
121 #endregion // Properties
128 context.ExitThread();
131 if (Application.ThreadExit != null)
132 Application.ThreadExit(null, EventArgs.Empty);
134 if (LoopCount == 0) {
135 if (Application.ApplicationExit != null)
136 Application.ApplicationExit (null, EventArgs.Empty);
139 ((MWFThread) threads [thread_id]).MessageLoop = false;
142 #endregion // Methods
145 private static bool browser_embedded;
146 private static InputLanguage input_language = InputLanguage.CurrentInputLanguage;
147 private static string safe_caption_format = "{1} - {0} - {2}";
148 private static readonly ArrayList message_filters = new ArrayList();
149 private static readonly FormCollection forms = new FormCollection ();
152 private static bool use_wait_cursor;
153 private static ToolStrip keyboard_capture;
155 private static VisualStyleState visual_style_state = VisualStyleState.ClientAndNonClientAreasEnabled;
156 static bool visual_styles_enabled;
158 private Application ()
163 static Application ()
165 // Attempt to load UIA support for winforms
166 // UIA support requires .NET 2.0
167 InitializeUIAutomation ();
171 #region Private Methods
174 private static void InitializeUIAutomation ()
176 // Initialize the UIAutomationWinforms FormListener
177 // class, which signs up for the PreRun and FormAdded
178 // events so that it can provide a11y support for MWF.
179 string uia_winforms_assembly = "UIAutomationWinforms, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f4ceacb585d99812";
180 string listener_type_name = string.Empty;
181 string init_method_name = "Initialize";
182 MethodInfo init_method;
184 Assembly mwf_providers = null;
186 mwf_providers = Assembly.Load (uia_winforms_assembly);
189 if (mwf_providers == null)
194 listener_type_name = "Mono.UIAutomation.Winforms.FormListener";
195 Type listener_type = mwf_providers.GetType (listener_type_name, false);
196 if (listener_type != null) {
197 init_method = listener_type.GetMethod (init_method_name, BindingFlags.Static | BindingFlags.Public);
198 if (init_method != null)
199 init_method.Invoke (null, new object [] {});
202 listener_type_name = "Mono.UIAutomation.Winforms.ToolTipListener";
203 listener_type = mwf_providers.GetType (listener_type_name, false);
204 if (listener_type != null) {
205 init_method = listener_type.GetMethod (init_method_name, BindingFlags.Static | BindingFlags.Public);
206 if (init_method != null)
207 init_method.Invoke (null, new object [] {});
209 //HelpProviderListener
210 listener_type_name = "Mono.UIAutomation.Winforms.HelpProviderListener";
211 listener_type = mwf_providers.GetType (listener_type_name, false);
212 if (listener_type != null) {
213 init_method = listener_type.GetMethod (init_method_name, BindingFlags.Static | BindingFlags.Public);
214 if (init_method != null)
215 init_method.Invoke (null, new object [] {});
217 //ErrorProviderListener
218 listener_type_name = "Mono.UIAutomation.Winforms.ErrorProviderListener";
219 listener_type = mwf_providers.GetType (listener_type_name, false);
220 if (listener_type != null) {
221 init_method = listener_type.GetMethod (init_method_name, BindingFlags.Static | BindingFlags.Public);
222 if (init_method != null)
223 init_method.Invoke (null, new object [] {});
231 internal static void CloseForms (Thread thread)
234 Console.WriteLine(" CloseForms({0}) called", thread);
237 ArrayList forms_to_close = new ArrayList ();
240 foreach (Form f in forms) {
241 if (thread == null || thread == f.creator_thread)
242 forms_to_close.Add (f);
245 foreach (Form f in forms_to_close) {
247 Console.WriteLine(" Closing form {0}", f);
254 #endregion // Private methods
256 #region Public Static Properties
258 public static bool AllowQuit {
260 return !browser_embedded;
264 public static string CommonAppDataPath {
266 return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData));
270 public static RegistryKey CommonAppDataRegistry {
272 string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
274 return Registry.LocalMachine.CreateSubKey (key);
278 public static string CompanyName {
280 string company = string.Empty;
282 Assembly assembly = Assembly.GetEntryAssembly ();
284 if (assembly == null)
285 assembly = Assembly.GetCallingAssembly ();
287 AssemblyCompanyAttribute[] attrs = (AssemblyCompanyAttribute[])
288 assembly.GetCustomAttributes (typeof(AssemblyCompanyAttribute), true);
289 if (attrs != null && attrs.Length > 0)
290 company = attrs [0].Company;
292 // If there is no [AssemblyCompany], return the outermost namespace
294 if (company == null || company.Length == 0)
295 if (assembly.EntryPoint != null) {
296 company = assembly.EntryPoint.DeclaringType.Namespace;
298 if (company != null) {
299 int firstDot = company.IndexOf ('.');
301 company = company.Substring (0, firstDot);
305 // If that doesn't work, return the name of class containing Main ()
306 if (company == null || company.Length == 0)
307 if (assembly.EntryPoint != null)
308 company = assembly.EntryPoint.DeclaringType.FullName;
314 public static CultureInfo CurrentCulture {
316 return Thread.CurrentThread.CurrentUICulture;
319 Thread.CurrentThread.CurrentUICulture = value;
323 public static InputLanguage CurrentInputLanguage {
325 return input_language;
328 input_language=value;
332 public static string ExecutablePath {
334 return Path.GetFullPath (Environment.GetCommandLineArgs ()[0]);
338 public static string LocalUserAppDataPath {
340 return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData));
344 public static bool MessageLoop {
346 return MWFThread.Current.MessageLoop;
350 public static string ProductName {
352 string name = string.Empty;
354 Assembly assembly = Assembly.GetEntryAssembly ();
356 if (assembly == null)
357 assembly = Assembly.GetCallingAssembly ();
359 AssemblyProductAttribute[] attrs = (AssemblyProductAttribute[])
360 assembly.GetCustomAttributes (typeof(AssemblyProductAttribute), true);
362 if (attrs != null && attrs.Length > 0)
363 name = attrs [0].Product;
365 // If there is no [AssemblyProduct], .NET returns the name of
366 // the innermost namespace and if that fails, resorts to the
367 // name of the class containing Main ()
368 if (name == null || name.Length == 0)
369 if (assembly.EntryPoint != null) {
370 name = assembly.EntryPoint.DeclaringType.Namespace;
373 int lastDot = name.LastIndexOf ('.');
374 if (lastDot >= 0 && lastDot < name.Length - 1)
375 name = name.Substring (lastDot + 1);
378 if (name == null || name.Length == 0)
379 name = assembly.EntryPoint.DeclaringType.FullName;
386 public static string ProductVersion {
388 String version = string.Empty;
390 Assembly assembly = Assembly.GetEntryAssembly ();
392 if (assembly == null)
393 assembly = Assembly.GetCallingAssembly ();
395 AssemblyInformationalVersionAttribute infoVersion =
396 Attribute.GetCustomAttribute (assembly,
397 typeof (AssemblyInformationalVersionAttribute))
398 as AssemblyInformationalVersionAttribute;
400 if (infoVersion != null)
401 version = infoVersion.InformationalVersion;
403 // If [AssemblyFileVersion] is present it is used
404 // before resorting to assembly version
405 if (version == null || version.Length == 0) {
406 AssemblyFileVersionAttribute fileVersion =
407 Attribute.GetCustomAttribute (assembly,
408 typeof (AssemblyFileVersionAttribute))
409 as AssemblyFileVersionAttribute;
410 if (fileVersion != null)
411 version = fileVersion.Version;
414 // If neither [AssemblyInformationalVersionAttribute]
415 // nor [AssemblyFileVersion] are present, then use
416 // the assembly version
417 if (version == null || version.Length == 0)
418 version = assembly.GetName ().Version.ToString ();
424 public static string SafeTopLevelCaptionFormat {
426 return safe_caption_format;
429 safe_caption_format = value;
433 public static string StartupPath {
435 return Path.GetDirectoryName (Application.ExecutablePath);
439 public static string UserAppDataPath {
441 return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData));
445 public static RegistryKey UserAppDataRegistry {
447 string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
449 return Registry.CurrentUser.CreateSubKey (key);
454 public static bool UseWaitCursor {
456 return use_wait_cursor;
459 use_wait_cursor = value;
460 if (use_wait_cursor) {
461 foreach (Form form in OpenForms) {
462 form.Cursor = Cursors.WaitCursor;
474 static bool RenderWithVisualStyles {
476 if (VisualStyleInformation.IsSupportedByOS) {
477 if (!VisualStyleInformation.IsEnabledByUser)
479 if (!XplatUI.ThemesEnabled)
481 if (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled)
483 if (Application.VisualStyleState == VisualStyleState.ClientAreaEnabled)
495 static VisualStyleState VisualStyleState {
496 get { return Application.visual_style_state; }
497 set { Application.visual_style_state = value; }
502 #region Public Static Methods
504 public static void AddMessageFilter (IMessageFilter value)
506 lock (message_filters) {
507 message_filters.Add (value);
511 internal static void AddKeyFilter (IKeyFilter value)
513 XplatUI.AddKeyFilter (value);
516 public static void DoEvents ()
521 public static void EnableVisualStyles ()
523 visual_styles_enabled = true;
524 XplatUI.EnableThemes ();
528 [EditorBrowsable (EditorBrowsableState.Advanced)]
531 static bool FilterMessage (ref Message message)
533 lock (message_filters) {
534 for (int i = 0; i < message_filters.Count; i++) {
535 IMessageFilter filter = (IMessageFilter) message_filters[i];
536 if (filter.PreFilterMessage (ref message))
545 // If true, it uses GDI+, performance reasons were quoted
547 static internal bool use_compatible_text_rendering = true;
549 public static void SetCompatibleTextRenderingDefault (bool defaultValue)
551 use_compatible_text_rendering = defaultValue;
554 public static FormCollection OpenForms {
560 [MonoNotSupported ("Only applies when Winforms is being hosted by an unmanaged app.")]
561 [EditorBrowsable (EditorBrowsableState.Advanced)]
562 public static void RegisterMessageLoop (MessageLoopCallback callback)
566 [MonoNotSupported ("Empty stub.")]
567 public static bool SetSuspendState (PowerState state, bool force, bool disableWakeEvent)
572 [MonoNotSupported ("Empty stub.")]
573 public static void SetUnhandledExceptionMode (UnhandledExceptionMode mode)
575 //FIXME: a stub to fill
578 [MonoNotSupported ("Empty stub.")]
579 public static void SetUnhandledExceptionMode (UnhandledExceptionMode mode, bool threadScope)
581 //FIXME: a stub to fill
584 [MonoNotSupported ("Only applies when Winforms is being hosted by an unmanaged app.")]
585 [EditorBrowsable (EditorBrowsableState.Advanced)]
586 public static void UnregisterMessageLoop ()
590 [EditorBrowsable (EditorBrowsableState.Advanced)]
591 public static void RaiseIdle (EventArgs e)
593 XplatUI.RaiseIdle (e);
596 public static void Restart ()
598 //FIXME: ClickOnce stuff using the Update or UpdateAsync methods.
599 //FIXME: SecurityPermission: Restart () requires IsUnrestricted permission.
601 if (Assembly.GetEntryAssembly () == null)
602 throw new NotSupportedException ("The method 'Restart' is not supported by this application type.");
604 string mono_path = null;
607 PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static | BindingFlags.NonPublic);
608 MethodInfo get_gac = null;
610 get_gac = gac.GetGetMethod (true);
612 if (get_gac != null) {
613 string gac_path = Path.GetDirectoryName ((string)get_gac.Invoke (null, null));
614 string mono_prefix = Path.GetDirectoryName (Path.GetDirectoryName (gac_path));
616 if (XplatUI.RunningOnUnix) {
617 mono_path = Path.Combine (mono_prefix, "bin/mono");
618 if (!File.Exists (mono_path))
621 mono_path = Path.Combine (mono_prefix, "bin\\mono.bat");
623 if (!File.Exists (mono_path))
624 mono_path = Path.Combine (mono_prefix, "bin\\mono.exe");
626 if (!File.Exists (mono_path))
627 mono_path = Path.Combine (mono_prefix, "mono\\mono\\mini\\mono.exe");
629 if (!File.Exists (mono_path))
630 throw new FileNotFoundException (string.Format ("Windows mono path not found: '{0}'", mono_path));
634 //Get command line arguments
635 StringBuilder argsBuilder = new StringBuilder ();
636 string[] args = Environment.GetCommandLineArgs ();
637 for (int i = 0; i < args.Length; i++)
639 argsBuilder.Append (string.Format ("\"{0}\" ", args[i]));
641 string arguments = argsBuilder.ToString ();
642 ProcessStartInfo procInfo = Process.GetCurrentProcess ().StartInfo;
644 if (mono_path == null) { //it is .NET on Windows
645 procInfo.FileName = args[0];
646 procInfo.Arguments = arguments.Remove (0, args[0].Length + 3); //1 space and 2 quotes
649 procInfo.Arguments = arguments;
650 procInfo.FileName = mono_path;
653 procInfo.WorkingDirectory = Environment.CurrentDirectory;
656 Process.Start (procInfo);
660 public static void Exit ()
663 Exit (new CancelEventArgs ());
665 XplatUI.PostQuitMessage (0);
671 [EditorBrowsable (EditorBrowsableState.Advanced)]
672 public static void Exit (CancelEventArgs e)
674 ArrayList forms_to_close;
677 forms_to_close = new ArrayList (forms);
679 foreach (Form f in forms_to_close) {
680 // Give each form a chance to cancel the Application.Exit
681 e.Cancel = f.FireClosingEvents (CloseReason.ApplicationExitCall, false);
686 f.suppress_closing_events = true;
692 XplatUI.PostQuitMessage (0);
696 public static void ExitThread()
698 CloseForms(Thread.CurrentThread);
699 // this might not be right - need to investigate (somehow) if a WM_QUIT message is generated here
700 XplatUI.PostQuitMessage(0);
703 public static ApartmentState OleRequired ()
705 //throw new NotImplementedException("OLE Not supported by this System.Windows.Forms implementation");
706 return ApartmentState.Unknown;
709 public static void OnThreadException (Exception t)
711 if (MWFThread.Current.HandlingException) {
712 /* we're already handling an exception and we got
713 another one? print it out and exit, this means
714 we've got a runtime/SWF bug. */
715 Console.WriteLine (t);
716 // Don't use Application.Exit here, since it may cause a stack overflow
717 // in certain cases. It's however hard to reproduce since it seems to
718 // be depending on when the GC kicks in.
723 MWFThread.Current.HandlingException = true;
725 if (Application.ThreadException != null) {
726 Application.ThreadException(null, new ThreadExceptionEventArgs(t));
730 if (SystemInformation.UserInteractive) {
731 Form form = new ThreadExceptionDialog (t);
734 Console.WriteLine (t.ToString ());
738 MWFThread.Current.HandlingException = false;
742 public static void RemoveMessageFilter (IMessageFilter value)
744 lock (message_filters) {
745 message_filters.Remove (value);
749 public static void Run ()
751 Run (new ApplicationContext ());
754 public static void Run (Form mainForm)
756 Run (new ApplicationContext (mainForm));
759 public static void Run (ApplicationContext context)
762 // Signal that the Application loop is about to run.
763 // This allows UIA to initialize a11y support for MWF
764 // before the main loop begins.
766 PreRun (null, EventArgs.Empty);
767 // If a sync context hasn't been created by now, create
769 if (SynchronizationContext.Current == null)
770 SynchronizationContext.SetSynchronizationContext (new SynchronizationContext ());
773 RunLoop (false, context);
776 // Reset the sync context back to the default
777 if (SynchronizationContext.Current is WindowsFormsSynchronizationContext)
778 WindowsFormsSynchronizationContext.Uninstall ();
782 private static void DisableFormsForModalLoop (Queue toplevels, ApplicationContext context)
787 IEnumerator control = forms.GetEnumerator ();
789 while (control.MoveNext ()) {
790 f = (Form)control.Current;
792 // Don't disable the main form.
793 if (f == context.MainForm) {
797 // Don't disable any children of the main form.
798 // These do not have to be MDI children.
800 bool is_child_of_main = false; ;
803 if (current.Parent == context.MainForm) {
804 is_child_of_main = true;
807 current = current.Parent;
808 } while (current != null);
810 if (is_child_of_main)
814 if (f.IsHandleCreated && XplatUI.IsEnabled (f.Handle)) {
816 Console.WriteLine(" Disabling form {0}", f);
818 XplatUI.EnableWindow (f.Handle, false);
819 toplevels.Enqueue (f);
827 private static void EnableFormsForModalLoop (Queue toplevels, ApplicationContext context)
829 while (toplevels.Count > 0) {
831 Console.WriteLine(" Re-Enabling form form {0}", toplevels.Peek());
833 Form c = (Form) toplevels.Dequeue ();
834 if (c.IsHandleCreated) {
835 XplatUI.EnableWindow (c.window.Handle, true);
836 context.MainForm = c;
840 Console.WriteLine(" Done with the re-enable");
844 internal static void RunLoop (bool Modal, ApplicationContext context)
850 ApplicationContext previous_thread_context;
852 thread = MWFThread.Current;
855 * There is a NotWorking test for this, but since we are using this method both for Form.ShowDialog as for ApplicationContexts we'll
856 * fail on nested ShowDialogs, so disable the check for the moment.
858 //if (thread.MessageLoop) {
859 // throw new InvalidOperationException ("Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.");
865 context = new ApplicationContext();
867 previous_thread_context = thread.Context;
868 thread.Context = context;
870 if (context.MainForm != null) {
871 context.MainForm.is_modal = Modal;
872 context.MainForm.context = context;
873 context.MainForm.closing = false;
874 context.MainForm.Visible = true; // Cannot use Show() or scaling gets confused by menus
875 // XXX the above line can be used to close the form. another problem with our handling of Show/Activate.
876 if (context.MainForm != null)
877 context.MainForm.Activate();
881 Console.WriteLine("Entering RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
885 toplevels = new Queue ();
886 DisableFormsForModalLoop (toplevels, context);
888 // FIXME - need activate?
889 /* make sure the MainForm is enabled */
890 if (context.MainForm != null) {
891 XplatUI.EnableWindow (context.MainForm.Handle, true);
892 XplatUI.SetModal(context.MainForm.Handle, true);
898 queue_id = XplatUI.StartLoop(Thread.CurrentThread);
899 thread.MessageLoop = true;
903 while (!quit && XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0)) {
904 Message m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
906 if (Application.FilterMessage (ref m))
909 switch((Msg)msg.message) {
911 case Msg.WM_SYSKEYDOWN:
915 case Msg.WM_SYSKEYUP:
917 c = Control.FromHandle(msg.hwnd);
920 // If we have a control with keyboard capture (usually a *Strip)
921 // give it the message, and then drop the message
922 if (keyboard_capture != null) {
923 // WM_SYSKEYUP does not make it into ProcessCmdKey, so do it here
924 if ((Msg)m.Msg == Msg.WM_SYSKEYUP)
925 if (m.WParam.ToInt32() == (int)Keys.Menu) {
926 keyboard_capture.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.Keyboard);
930 m.HWnd = keyboard_capture.Handle;
932 switch (keyboard_capture.PreProcessControlMessageInternal (ref m)) {
933 case PreProcessControlState.MessageProcessed:
935 case PreProcessControlState.MessageNeeded:
936 case PreProcessControlState.MessageNotNeeded:
937 if (((m.Msg == (int)Msg.WM_KEYDOWN || m.Msg == (int)Msg.WM_CHAR) && !keyboard_capture.ProcessControlMnemonic ((char)m.WParam))) {
938 if (c == null || !ControlOnToolStrip (c))
950 if (((c != null) && c.PreProcessControlMessageInternal (ref m) != PreProcessControlState.MessageProcessed) ||
956 case Msg.WM_LBUTTONDOWN:
957 case Msg.WM_MBUTTONDOWN:
958 case Msg.WM_RBUTTONDOWN:
959 if (keyboard_capture != null) {
960 Control c2 = Control.FromHandle (msg.hwnd);
962 // If we clicked a ToolStrip, we have to make sure it isn't
963 // the one we are on, or any of its parents or children
964 // If we clicked off the dropped down menu, release everything
965 if (c2 is ToolStrip) {
966 if ((c2 as ToolStrip).GetTopLevelToolStrip () != keyboard_capture.GetTopLevelToolStrip ())
967 ToolStripManager.FireAppClicked ();
969 if (c2.Parent != null)
970 if (c2.Parent is ToolStripDropDownMenu)
971 if ((c2.Parent as ToolStripDropDownMenu).GetTopLevelToolStrip () == keyboard_capture.GetTopLevelToolStrip ())
973 if (c2.TopLevelControl == null)
976 ToolStripManager.FireAppClicked ();
983 quit = true; // make sure we exit
986 XplatUI.TranslateMessage (ref msg);
987 XplatUI.DispatchMessage (ref msg);
991 // Handle exit, Form might have received WM_CLOSE and set 'closing' in response
992 if ((context.MainForm != null) && (context.MainForm.closing || (Modal && !context.MainForm.Visible))) {
994 XplatUI.PostQuitMessage (0);
1001 Console.WriteLine (" RunLoop loop left");
1004 thread.MessageLoop = false;
1005 XplatUI.EndLoop (Thread.CurrentThread);
1008 Form old = context.MainForm;
1010 context.MainForm = null;
1012 EnableFormsForModalLoop (toplevels, context);
1014 if (context.MainForm != null && context.MainForm.IsHandleCreated) {
1015 XplatUI.SetModal (context.MainForm.Handle, false);
1018 Console.WriteLine (" Done with the SetModal");
1020 old.RaiseCloseEvents (true, false);
1021 old.is_modal = false;
1025 Console.WriteLine ("Leaving RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
1028 if (context.MainForm != null) {
1029 context.MainForm.context = null;
1030 context.MainForm = null;
1033 thread.Context = previous_thread_context;
1039 #endregion // Public Static Methods
1043 public static event EventHandler ApplicationExit;
1045 public static event EventHandler Idle {
1047 XplatUI.Idle += value;
1050 XplatUI.Idle -= value;
1054 public static event EventHandler ThreadExit;
1055 public static event ThreadExceptionEventHandler ThreadException;
1058 // These are used externally by the UIA framework
1059 internal static event EventHandler FormAdded;
1060 internal static event EventHandler PreRun;
1062 [EditorBrowsable (EditorBrowsableState.Advanced)]
1063 public static event EventHandler EnterThreadModal;
1065 [EditorBrowsable (EditorBrowsableState.Advanced)]
1066 public static event EventHandler LeaveThreadModal;
1069 #endregion // Events
1071 #region Public Delegates
1074 [EditorBrowsable (EditorBrowsableState.Advanced)]
1075 public delegate bool MessageLoopCallback ();
1080 #region Internal Properties
1082 internal static ToolStrip KeyboardCapture {
1083 get { return keyboard_capture; }
1084 set { keyboard_capture = value; }
1088 internal static bool VisualStylesEnabled {
1089 get { return visual_styles_enabled; }
1093 #region Internal Methods
1095 internal static void AddForm (Form f)
1100 // Signal that a Form has been added to this
1101 // Application. Used by UIA to detect new Forms that
1102 // need a11y support. This event may be fired even if
1103 // the form has already been added, so clients should
1104 // account for that when handling this signal.
1105 if (FormAdded != null)
1106 FormAdded (f, null);
1110 internal static void RemoveForm (Form f)
1117 private static bool ControlOnToolStrip (Control c)
1119 Control p = c.Parent;
1132 // Takes a starting path, appends company name, product name, and
1133 // product version. If the directory doesn't exist, create it
1134 private static string CreateDataPath (string basePath)
1138 path = Path.Combine (basePath, CompanyName);
1139 path = Path.Combine (path, ProductName);
1140 path = Path.Combine (path, ProductVersion);
1142 if (!Directory.Exists (path))
1143 Directory.CreateDirectory (path);