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 ()
160 browser_embedded = false;
164 static Application ()
166 // Attempt to load UIA support for winforms
167 // UIA support requires .NET 2.0
168 InitializeUIAutomation ();
172 #region Private Methods
176 private static void InitializeUIAutomation ()
178 // Initialize the UIAutomationWinforms Global class,
179 // which create some listeners which subscribe to internal
180 // MWF events so that it can provide a11y support for MWF
181 const string UIA_WINFORMS_ASSEMBLY =
182 "UIAutomationWinforms, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f4ceacb585d99812";
183 MethodInfo init_method;
184 Assembly mwf_providers = null;
186 mwf_providers = Assembly.Load (UIA_WINFORMS_ASSEMBLY);
189 if (mwf_providers == null)
192 const string UIA_WINFORMS_TYPE = "Mono.UIAutomation.Winforms.Global";
193 const string UIA_WINFORMS_METHOD = "Initialize";
195 Type global_type = mwf_providers.GetType (UIA_WINFORMS_TYPE, false);
196 if (global_type != null) {
197 init_method = global_type.GetMethod (UIA_WINFORMS_METHOD,
198 BindingFlags.Static |
199 BindingFlags.Public);
200 if (init_method != null)
201 init_method.Invoke (null, new object [] {});
203 throw new Exception (String.Format ("Method {0} not found in type {1}.",
204 UIA_WINFORMS_METHOD, UIA_WINFORMS_TYPE));
207 throw new Exception (String.Format ("Type {0} not found in assembly {1}.",
208 UIA_WINFORMS_TYPE, UIA_WINFORMS_ASSEMBLY));
209 } catch (Exception ex) {
210 Console.Error.WriteLine ("Error setting up UIA: " + ex);
215 internal static void CloseForms (Thread thread)
218 Console.WriteLine(" CloseForms({0}) called", thread);
221 ArrayList forms_to_close = new ArrayList ();
224 foreach (Form f in forms) {
225 if (thread == null || thread == f.creator_thread)
226 forms_to_close.Add (f);
229 foreach (Form f in forms_to_close) {
231 Console.WriteLine(" Closing form {0}", f);
238 #endregion // Private methods
240 #region Public Static Properties
242 public static bool AllowQuit {
244 return !browser_embedded;
248 public static string CommonAppDataPath {
250 return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData));
254 public static RegistryKey CommonAppDataRegistry {
256 string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
258 return Registry.LocalMachine.CreateSubKey (key);
262 public static string CompanyName {
264 string company = string.Empty;
266 Assembly assembly = Assembly.GetEntryAssembly ();
268 if (assembly == null)
269 assembly = Assembly.GetCallingAssembly ();
271 AssemblyCompanyAttribute[] attrs = (AssemblyCompanyAttribute[])
272 assembly.GetCustomAttributes (typeof(AssemblyCompanyAttribute), true);
273 if (attrs != null && attrs.Length > 0)
274 company = attrs [0].Company;
276 // If there is no [AssemblyCompany], return the outermost namespace
278 if (company == null || company.Length == 0)
279 if (assembly.EntryPoint != null) {
280 company = assembly.EntryPoint.DeclaringType.Namespace;
282 if (company != null) {
283 int firstDot = company.IndexOf ('.');
285 company = company.Substring (0, firstDot);
289 // If that doesn't work, return the name of class containing Main ()
290 if (company == null || company.Length == 0)
291 if (assembly.EntryPoint != null)
292 company = assembly.EntryPoint.DeclaringType.FullName;
298 public static CultureInfo CurrentCulture {
300 return Thread.CurrentThread.CurrentUICulture;
303 Thread.CurrentThread.CurrentUICulture = value;
307 public static InputLanguage CurrentInputLanguage {
309 return input_language;
312 input_language=value;
316 public static string ExecutablePath {
318 return Path.GetFullPath (Environment.GetCommandLineArgs ()[0]);
322 public static string LocalUserAppDataPath {
324 return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData));
328 public static bool MessageLoop {
330 return MWFThread.Current.MessageLoop;
334 public static string ProductName {
336 string name = string.Empty;
338 Assembly assembly = Assembly.GetEntryAssembly ();
340 if (assembly == null)
341 assembly = Assembly.GetCallingAssembly ();
343 AssemblyProductAttribute[] attrs = (AssemblyProductAttribute[])
344 assembly.GetCustomAttributes (typeof(AssemblyProductAttribute), true);
346 if (attrs != null && attrs.Length > 0)
347 name = attrs [0].Product;
349 // If there is no [AssemblyProduct], .NET returns the name of
350 // the innermost namespace and if that fails, resorts to the
351 // name of the class containing Main ()
352 if (name == null || name.Length == 0)
353 if (assembly.EntryPoint != null) {
354 name = assembly.EntryPoint.DeclaringType.Namespace;
357 int lastDot = name.LastIndexOf ('.');
358 if (lastDot >= 0 && lastDot < name.Length - 1)
359 name = name.Substring (lastDot + 1);
362 if (name == null || name.Length == 0)
363 name = assembly.EntryPoint.DeclaringType.FullName;
370 public static string ProductVersion {
372 String version = string.Empty;
374 Assembly assembly = Assembly.GetEntryAssembly ();
376 if (assembly == null)
377 assembly = Assembly.GetCallingAssembly ();
379 AssemblyInformationalVersionAttribute infoVersion =
380 Attribute.GetCustomAttribute (assembly,
381 typeof (AssemblyInformationalVersionAttribute))
382 as AssemblyInformationalVersionAttribute;
384 if (infoVersion != null)
385 version = infoVersion.InformationalVersion;
387 // If [AssemblyFileVersion] is present it is used
388 // before resorting to assembly version
389 if (version == null || version.Length == 0) {
390 AssemblyFileVersionAttribute fileVersion =
391 Attribute.GetCustomAttribute (assembly,
392 typeof (AssemblyFileVersionAttribute))
393 as AssemblyFileVersionAttribute;
394 if (fileVersion != null)
395 version = fileVersion.Version;
398 // If neither [AssemblyInformationalVersionAttribute]
399 // nor [AssemblyFileVersion] are present, then use
400 // the assembly version
401 if (version == null || version.Length == 0)
402 version = assembly.GetName ().Version.ToString ();
408 public static string SafeTopLevelCaptionFormat {
410 return safe_caption_format;
413 safe_caption_format = value;
417 public static string StartupPath {
419 return Path.GetDirectoryName (Application.ExecutablePath);
423 public static string UserAppDataPath {
425 return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData));
429 public static RegistryKey UserAppDataRegistry {
431 string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
433 return Registry.CurrentUser.CreateSubKey (key);
438 public static bool UseWaitCursor {
440 return use_wait_cursor;
443 use_wait_cursor = value;
444 if (use_wait_cursor) {
445 foreach (Form form in OpenForms) {
446 form.Cursor = Cursors.WaitCursor;
458 static bool RenderWithVisualStyles {
460 if (VisualStyleInformation.IsSupportedByOS) {
461 if (!VisualStyleInformation.IsEnabledByUser)
463 if (!XplatUI.ThemesEnabled)
465 if (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled)
467 if (Application.VisualStyleState == VisualStyleState.ClientAreaEnabled)
479 static VisualStyleState VisualStyleState {
480 get { return Application.visual_style_state; }
481 set { Application.visual_style_state = value; }
486 #region Public Static Methods
488 public static void AddMessageFilter (IMessageFilter value)
490 lock (message_filters) {
491 message_filters.Add (value);
495 internal static void AddKeyFilter (IKeyFilter value)
497 XplatUI.AddKeyFilter (value);
500 public static void DoEvents ()
505 public static void EnableVisualStyles ()
507 visual_styles_enabled = true;
508 XplatUI.EnableThemes ();
512 [EditorBrowsable (EditorBrowsableState.Advanced)]
517 static bool FilterMessage (ref Message message)
519 lock (message_filters) {
520 for (int i = 0; i < message_filters.Count; i++) {
521 IMessageFilter filter = (IMessageFilter) message_filters[i];
522 if (filter.PreFilterMessage (ref message))
531 // If true, it uses GDI+, performance reasons were quoted
533 static internal bool use_compatible_text_rendering = true;
535 public static void SetCompatibleTextRenderingDefault (bool defaultValue)
537 use_compatible_text_rendering = defaultValue;
540 public static FormCollection OpenForms {
546 [MonoNotSupported ("Only applies when Winforms is being hosted by an unmanaged app.")]
547 [EditorBrowsable (EditorBrowsableState.Advanced)]
548 public static void RegisterMessageLoop (MessageLoopCallback callback)
552 [MonoNotSupported ("Empty stub.")]
553 public static bool SetSuspendState (PowerState state, bool force, bool disableWakeEvent)
558 [MonoNotSupported ("Empty stub.")]
559 public static void SetUnhandledExceptionMode (UnhandledExceptionMode mode)
561 //FIXME: a stub to fill
564 [MonoNotSupported ("Empty stub.")]
565 public static void SetUnhandledExceptionMode (UnhandledExceptionMode mode, bool threadScope)
567 //FIXME: a stub to fill
570 [MonoNotSupported ("Only applies when Winforms is being hosted by an unmanaged app.")]
571 [EditorBrowsable (EditorBrowsableState.Advanced)]
572 public static void UnregisterMessageLoop ()
576 [EditorBrowsable (EditorBrowsableState.Advanced)]
577 public static void RaiseIdle (EventArgs e)
579 XplatUI.RaiseIdle (e);
582 public static void Restart ()
584 //FIXME: ClickOnce stuff using the Update or UpdateAsync methods.
585 //FIXME: SecurityPermission: Restart () requires IsUnrestricted permission.
587 if (Assembly.GetEntryAssembly () == null)
588 throw new NotSupportedException ("The method 'Restart' is not supported by this application type.");
590 string mono_path = null;
593 PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static | BindingFlags.NonPublic);
594 MethodInfo get_gac = null;
596 get_gac = gac.GetGetMethod (true);
598 if (get_gac != null) {
599 string gac_path = Path.GetDirectoryName ((string)get_gac.Invoke (null, null));
600 string mono_prefix = Path.GetDirectoryName (Path.GetDirectoryName (gac_path));
602 if (XplatUI.RunningOnUnix) {
603 mono_path = Path.Combine (mono_prefix, "bin/mono");
604 if (!File.Exists (mono_path))
607 mono_path = Path.Combine (mono_prefix, "bin\\mono.bat");
609 if (!File.Exists (mono_path))
610 mono_path = Path.Combine (mono_prefix, "bin\\mono.exe");
612 if (!File.Exists (mono_path))
613 mono_path = Path.Combine (mono_prefix, "mono\\mono\\mini\\mono.exe");
615 if (!File.Exists (mono_path))
616 throw new FileNotFoundException (string.Format ("Windows mono path not found: '{0}'", mono_path));
620 //Get command line arguments
621 StringBuilder argsBuilder = new StringBuilder ();
622 string[] args = Environment.GetCommandLineArgs ();
623 for (int i = 0; i < args.Length; i++)
625 argsBuilder.Append (string.Format ("\"{0}\" ", args[i]));
627 string arguments = argsBuilder.ToString ();
628 ProcessStartInfo procInfo = Process.GetCurrentProcess ().StartInfo;
630 if (mono_path == null) { //it is .NET on Windows
631 procInfo.FileName = args[0];
632 procInfo.Arguments = arguments.Remove (0, args[0].Length + 3); //1 space and 2 quotes
635 procInfo.Arguments = arguments;
636 procInfo.FileName = mono_path;
639 procInfo.WorkingDirectory = Environment.CurrentDirectory;
642 Process.Start (procInfo);
646 public static void Exit ()
649 Exit (new CancelEventArgs ());
651 XplatUI.PostQuitMessage (0);
657 [EditorBrowsable (EditorBrowsableState.Advanced)]
658 public static void Exit (CancelEventArgs e)
660 ArrayList forms_to_close;
663 forms_to_close = new ArrayList (forms);
665 foreach (Form f in forms_to_close) {
666 // Give each form a chance to cancel the Application.Exit
667 e.Cancel = f.FireClosingEvents (CloseReason.ApplicationExitCall, false);
672 f.suppress_closing_events = true;
678 XplatUI.PostQuitMessage (0);
682 public static void ExitThread()
684 CloseForms(Thread.CurrentThread);
685 // this might not be right - need to investigate (somehow) if a WM_QUIT message is generated here
686 XplatUI.PostQuitMessage(0);
689 public static ApartmentState OleRequired ()
691 //throw new NotImplementedException("OLE Not supported by this System.Windows.Forms implementation");
692 return ApartmentState.Unknown;
695 public static void OnThreadException (Exception t)
697 if (MWFThread.Current.HandlingException) {
698 /* we're already handling an exception and we got
699 another one? print it out and exit, this means
700 we've got a runtime/SWF bug. */
701 Console.WriteLine (t);
702 // Don't use Application.Exit here, since it may cause a stack overflow
703 // in certain cases. It's however hard to reproduce since it seems to
704 // be depending on when the GC kicks in.
709 MWFThread.Current.HandlingException = true;
711 if (Application.ThreadException != null) {
712 Application.ThreadException(null, new ThreadExceptionEventArgs(t));
716 if (SystemInformation.UserInteractive) {
717 Form form = new ThreadExceptionDialog (t);
720 Console.WriteLine (t.ToString ());
724 MWFThread.Current.HandlingException = false;
728 public static void RemoveMessageFilter (IMessageFilter value)
730 lock (message_filters) {
731 message_filters.Remove (value);
735 public static void Run ()
737 Run (new ApplicationContext ());
740 public static void Run (Form mainForm)
742 Run (new ApplicationContext (mainForm));
746 internal static void FirePreRun ()
748 EventHandler handler = PreRun;
750 handler (null, EventArgs.Empty);
754 public static void Run (ApplicationContext context)
757 // If a sync context hasn't been created by now, create
759 if (SynchronizationContext.Current == null)
760 SynchronizationContext.SetSynchronizationContext (new SynchronizationContext ());
763 RunLoop (false, context);
766 // Reset the sync context back to the default
767 if (SynchronizationContext.Current is WindowsFormsSynchronizationContext)
768 WindowsFormsSynchronizationContext.Uninstall ();
772 private static void DisableFormsForModalLoop (Queue toplevels, ApplicationContext context)
777 IEnumerator control = forms.GetEnumerator ();
779 while (control.MoveNext ()) {
780 f = (Form)control.Current;
782 // Don't disable the main form.
783 if (f == context.MainForm) {
787 // Don't disable any children of the main form.
788 // These do not have to be MDI children.
790 bool is_child_of_main = false; ;
793 if (current.Parent == context.MainForm) {
794 is_child_of_main = true;
797 current = current.Parent;
798 } while (current != null);
800 if (is_child_of_main)
804 if (f.IsHandleCreated && XplatUI.IsEnabled (f.Handle)) {
806 Console.WriteLine(" Disabling form {0}", f);
808 XplatUI.EnableWindow (f.Handle, false);
809 toplevels.Enqueue (f);
817 private static void EnableFormsForModalLoop (Queue toplevels, ApplicationContext context)
819 while (toplevels.Count > 0) {
821 Console.WriteLine(" Re-Enabling form form {0}", toplevels.Peek());
823 Form c = (Form) toplevels.Dequeue ();
824 if (c.IsHandleCreated) {
825 XplatUI.EnableWindow (c.window.Handle, true);
826 context.MainForm = c;
830 Console.WriteLine(" Done with the re-enable");
834 internal static void RunLoop (bool Modal, ApplicationContext context)
840 ApplicationContext previous_thread_context;
842 thread = MWFThread.Current;
845 * There is a NotWorking test for this, but since we are using this method both for Form.ShowDialog as for ApplicationContexts we'll
846 * fail on nested ShowDialogs, so disable the check for the moment.
848 //if (thread.MessageLoop) {
849 // throw new InvalidOperationException ("Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.");
855 context = new ApplicationContext();
857 previous_thread_context = thread.Context;
858 thread.Context = context;
860 if (context.MainForm != null) {
861 context.MainForm.is_modal = Modal;
862 context.MainForm.context = context;
863 context.MainForm.closing = false;
864 context.MainForm.Visible = true; // Cannot use Show() or scaling gets confused by menus
865 // XXX the above line can be used to close the form. another problem with our handling of Show/Activate.
866 if (context.MainForm != null)
867 context.MainForm.Activate();
871 Console.WriteLine("Entering RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
875 toplevels = new Queue ();
876 DisableFormsForModalLoop (toplevels, context);
878 // FIXME - need activate?
879 /* make sure the MainForm is enabled */
880 if (context.MainForm != null) {
881 XplatUI.EnableWindow (context.MainForm.Handle, true);
882 XplatUI.SetModal(context.MainForm.Handle, true);
888 queue_id = XplatUI.StartLoop(Thread.CurrentThread);
889 thread.MessageLoop = true;
893 while (!quit && XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0)) {
894 Message m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
896 if (Application.FilterMessage (ref m))
899 switch((Msg)msg.message) {
901 case Msg.WM_SYSKEYDOWN:
905 case Msg.WM_SYSKEYUP:
907 c = Control.FromHandle(msg.hwnd);
910 // If we have a control with keyboard capture (usually a *Strip)
911 // give it the message, and then drop the message
912 if (keyboard_capture != null) {
913 // WM_SYSKEYUP does not make it into ProcessCmdKey, so do it here
914 if ((Msg)m.Msg == Msg.WM_SYSKEYDOWN)
915 if (m.WParam.ToInt32() == (int)Keys.Menu) {
916 keyboard_capture.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.Keyboard);
920 m.HWnd = keyboard_capture.Handle;
922 switch (keyboard_capture.PreProcessControlMessageInternal (ref m)) {
923 case PreProcessControlState.MessageProcessed:
925 case PreProcessControlState.MessageNeeded:
926 case PreProcessControlState.MessageNotNeeded:
927 if (((m.Msg == (int)Msg.WM_KEYDOWN || m.Msg == (int)Msg.WM_CHAR) && !keyboard_capture.ProcessControlMnemonic ((char)m.WParam))) {
928 if (c == null || !ControlOnToolStrip (c))
940 if (((c != null) && c.PreProcessControlMessageInternal (ref m) != PreProcessControlState.MessageProcessed) ||
946 case Msg.WM_LBUTTONDOWN:
947 case Msg.WM_MBUTTONDOWN:
948 case Msg.WM_RBUTTONDOWN:
949 if (keyboard_capture != null) {
950 Control c2 = Control.FromHandle (msg.hwnd);
952 // the target is not a winforms control (an embedded control, perhaps), so
953 // release everything
955 ToolStripManager.FireAppClicked ();
959 // If we clicked a ToolStrip, we have to make sure it isn't
960 // the one we are on, or any of its parents or children
961 // If we clicked off the dropped down menu, release everything
962 if (c2 is ToolStrip) {
963 if ((c2 as ToolStrip).GetTopLevelToolStrip () != keyboard_capture.GetTopLevelToolStrip ())
964 ToolStripManager.FireAppClicked ();
966 if (c2.Parent != null)
967 if (c2.Parent is ToolStripDropDownMenu)
968 if ((c2.Parent as ToolStripDropDownMenu).GetTopLevelToolStrip () == keyboard_capture.GetTopLevelToolStrip ())
970 if (c2.TopLevelControl == null)
973 ToolStripManager.FireAppClicked ();
980 quit = true; // make sure we exit
983 XplatUI.TranslateMessage (ref msg);
984 XplatUI.DispatchMessage (ref msg);
988 // Handle exit, Form might have received WM_CLOSE and set 'closing' in response
989 if ((context.MainForm != null) && (context.MainForm.closing || (Modal && !context.MainForm.Visible))) {
991 XplatUI.PostQuitMessage (0);
998 Console.WriteLine (" RunLoop loop left");
1001 thread.MessageLoop = false;
1002 XplatUI.EndLoop (Thread.CurrentThread);
1005 Form old = context.MainForm;
1007 context.MainForm = null;
1009 EnableFormsForModalLoop (toplevels, context);
1011 if (context.MainForm != null && context.MainForm.IsHandleCreated) {
1012 XplatUI.SetModal (context.MainForm.Handle, false);
1015 Console.WriteLine (" Done with the SetModal");
1017 old.RaiseCloseEvents (true, false);
1018 old.is_modal = false;
1022 Console.WriteLine ("Leaving RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
1025 if (context.MainForm != null) {
1026 context.MainForm.context = null;
1027 context.MainForm = null;
1030 thread.Context = previous_thread_context;
1036 #endregion // Public Static Methods
1040 public static event EventHandler ApplicationExit;
1042 public static event EventHandler Idle {
1044 XplatUI.Idle += value;
1047 XplatUI.Idle -= value;
1051 public static event EventHandler ThreadExit;
1052 public static event ThreadExceptionEventHandler ThreadException;
1055 // These are used externally by the UIA framework
1056 internal static event EventHandler FormAdded;
1057 internal static event EventHandler PreRun;
1059 [EditorBrowsable (EditorBrowsableState.Advanced)]
1060 public static event EventHandler EnterThreadModal;
1062 [EditorBrowsable (EditorBrowsableState.Advanced)]
1063 public static event EventHandler LeaveThreadModal;
1066 #endregion // Events
1068 #region Public Delegates
1071 [EditorBrowsable (EditorBrowsableState.Advanced)]
1072 public delegate bool MessageLoopCallback ();
1077 #region Internal Properties
1079 internal static ToolStrip KeyboardCapture {
1080 get { return keyboard_capture; }
1081 set { keyboard_capture = value; }
1085 internal static bool VisualStylesEnabled {
1086 get { return visual_styles_enabled; }
1090 #region Internal Methods
1092 internal static void AddForm (Form f)
1097 // Signal that a Form has been added to this
1098 // Application. Used by UIA to detect new Forms that
1099 // need a11y support. This event may be fired even if
1100 // the form has already been added, so clients should
1101 // account for that when handling this signal.
1102 if (FormAdded != null)
1103 FormAdded (f, null);
1107 internal static void RemoveForm (Form f)
1114 private static bool ControlOnToolStrip (Control c)
1116 Control p = c.Parent;
1129 // Takes a starting path, appends company name, product name, and
1130 // product version. If the directory doesn't exist, create it
1131 private static string CreateDataPath (string basePath)
1135 path = Path.Combine (basePath, CompanyName);
1136 path = Path.Combine (path, ProductName);
1137 path = Path.Combine (path, ProductVersion);
1139 if (!Directory.Exists (path))
1140 Directory.CreateDirectory (path);