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;
43 using System.Windows.Forms.VisualStyles;
45 namespace System.Windows.Forms
47 public sealed class Application
49 internal class MWFThread
53 private ApplicationContext context;
54 private bool messageloop_started;
55 private bool handling_exception;
56 private int thread_id;
58 private static readonly Hashtable threads = new Hashtable();
68 #endregion // Constructors
72 public ApplicationContext Context {
73 get { return context; }
74 set { context = value; }
77 public bool MessageLoop {
78 get { return messageloop_started; }
79 set { messageloop_started = value; }
82 public bool HandlingException {
83 get { return handling_exception; }
84 set { handling_exception = value; }
87 public static int LoopCount {
92 foreach (MWFThread thread in threads.Values) {
93 if (thread.messageloop_started)
102 public static MWFThread Current {
104 MWFThread thread = null;
107 thread = (MWFThread) threads [Thread.CurrentThread.GetHashCode ()];
108 if (thread == null) {
109 thread = new MWFThread();
110 thread.thread_id = Thread.CurrentThread.GetHashCode ();
111 threads [thread.thread_id] = thread;
119 #endregion // Properties
126 context.ExitThread();
129 if (Application.ThreadExit != null)
130 Application.ThreadExit(null, EventArgs.Empty);
132 if (LoopCount == 0) {
133 if (Application.ApplicationExit != null)
134 Application.ApplicationExit (null, EventArgs.Empty);
137 ((MWFThread) threads [thread_id]).MessageLoop = false;
140 #endregion // Methods
143 private static bool browser_embedded;
144 private static InputLanguage input_language = InputLanguage.CurrentInputLanguage;
145 private static string safe_caption_format = "{1} - {0} - {2}";
146 private static readonly ArrayList message_filters = new ArrayList();
147 private static readonly FormCollection forms = new FormCollection ();
149 private static bool use_wait_cursor;
150 private static ToolStrip keyboard_capture;
151 private static VisualStyleState visual_style_state = VisualStyleState.ClientAndNonClientAreasEnabled;
152 static bool visual_styles_enabled;
154 private Application ()
156 browser_embedded = false;
159 static Application ()
161 // Attempt to load UIA support for winforms
162 // UIA support requires .NET 2.0
163 InitializeUIAutomation ();
166 #region Private Methods
168 private static void InitializeUIAutomation ()
170 // Initialize the UIAutomationWinforms Global class,
171 // which create some listeners which subscribe to internal
172 // MWF events so that it can provide a11y support for MWF
173 const string UIA_WINFORMS_ASSEMBLY =
174 "UIAutomationWinforms, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f4ceacb585d99812";
175 MethodInfo init_method;
176 Assembly mwf_providers = null;
178 mwf_providers = Assembly.Load (UIA_WINFORMS_ASSEMBLY);
181 if (mwf_providers == null)
184 const string UIA_WINFORMS_TYPE = "Mono.UIAutomation.Winforms.Global";
185 const string UIA_WINFORMS_METHOD = "Initialize";
187 Type global_type = mwf_providers.GetType (UIA_WINFORMS_TYPE, false);
188 if (global_type != null) {
189 init_method = global_type.GetMethod (UIA_WINFORMS_METHOD,
190 BindingFlags.Static |
191 BindingFlags.Public);
192 if (init_method != null)
193 init_method.Invoke (null, new object [] {});
195 throw new Exception (String.Format ("Method {0} not found in type {1}.",
196 UIA_WINFORMS_METHOD, UIA_WINFORMS_TYPE));
199 throw new Exception (String.Format ("Type {0} not found in assembly {1}.",
200 UIA_WINFORMS_TYPE, UIA_WINFORMS_ASSEMBLY));
201 } catch (Exception ex) {
202 Console.Error.WriteLine ("Error setting up UIA: " + ex);
206 internal static void CloseForms (Thread thread)
209 Console.WriteLine(" CloseForms({0}) called", thread);
212 ArrayList forms_to_close = new ArrayList ();
215 foreach (Form f in forms) {
216 if (thread == null || thread == f.creator_thread)
217 forms_to_close.Add (f);
220 foreach (Form f in forms_to_close) {
222 Console.WriteLine(" Closing form {0}", f);
229 #endregion // Private methods
231 #region Public Static Properties
233 public static bool AllowQuit {
235 return !browser_embedded;
239 public static string CommonAppDataPath {
241 return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData));
245 public static RegistryKey CommonAppDataRegistry {
247 string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
249 return Registry.LocalMachine.CreateSubKey (key);
253 public static string CompanyName {
255 string company = string.Empty;
257 Assembly assembly = Assembly.GetEntryAssembly ();
259 if (assembly == null)
260 assembly = Assembly.GetCallingAssembly ();
262 AssemblyCompanyAttribute[] attrs = (AssemblyCompanyAttribute[])
263 assembly.GetCustomAttributes (typeof(AssemblyCompanyAttribute), true);
264 if (attrs != null && attrs.Length > 0)
265 company = attrs [0].Company;
267 // If there is no [AssemblyCompany], return the outermost namespace
269 if (company == null || company.Length == 0)
270 if (assembly.EntryPoint != null) {
271 company = assembly.EntryPoint.DeclaringType.Namespace;
273 if (company != null) {
274 int firstDot = company.IndexOf ('.');
276 company = company.Substring (0, firstDot);
280 // If that doesn't work, return the name of class containing Main ()
281 if (company == null || company.Length == 0)
282 if (assembly.EntryPoint != null)
283 company = assembly.EntryPoint.DeclaringType.FullName;
289 public static CultureInfo CurrentCulture {
291 return Thread.CurrentThread.CurrentUICulture;
294 Thread.CurrentThread.CurrentUICulture = value;
298 public static InputLanguage CurrentInputLanguage {
300 return input_language;
303 input_language=value;
307 public static string ExecutablePath {
309 return Path.GetFullPath (Environment.GetCommandLineArgs ()[0]);
313 public static string LocalUserAppDataPath {
315 return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData));
319 public static bool MessageLoop {
321 return MWFThread.Current.MessageLoop;
325 public static string ProductName {
327 string name = string.Empty;
329 Assembly assembly = Assembly.GetEntryAssembly ();
331 if (assembly == null)
332 assembly = Assembly.GetCallingAssembly ();
334 AssemblyProductAttribute[] attrs = (AssemblyProductAttribute[])
335 assembly.GetCustomAttributes (typeof(AssemblyProductAttribute), true);
337 if (attrs != null && attrs.Length > 0)
338 name = attrs [0].Product;
340 // If there is no [AssemblyProduct], .NET returns the name of
341 // the innermost namespace and if that fails, resorts to the
342 // name of the class containing Main ()
343 if (name == null || name.Length == 0)
344 if (assembly.EntryPoint != null) {
345 name = assembly.EntryPoint.DeclaringType.Namespace;
348 int lastDot = name.LastIndexOf ('.');
349 if (lastDot >= 0 && lastDot < name.Length - 1)
350 name = name.Substring (lastDot + 1);
353 if (name == null || name.Length == 0)
354 name = assembly.EntryPoint.DeclaringType.FullName;
361 public static string ProductVersion {
363 String version = string.Empty;
365 Assembly assembly = Assembly.GetEntryAssembly ();
367 if (assembly == null)
368 assembly = Assembly.GetCallingAssembly ();
370 AssemblyInformationalVersionAttribute infoVersion =
371 Attribute.GetCustomAttribute (assembly,
372 typeof (AssemblyInformationalVersionAttribute))
373 as AssemblyInformationalVersionAttribute;
375 if (infoVersion != null)
376 version = infoVersion.InformationalVersion;
378 // If [AssemblyFileVersion] is present it is used
379 // before resorting to assembly version
380 if (version == null || version.Length == 0) {
381 AssemblyFileVersionAttribute fileVersion =
382 Attribute.GetCustomAttribute (assembly,
383 typeof (AssemblyFileVersionAttribute))
384 as AssemblyFileVersionAttribute;
385 if (fileVersion != null)
386 version = fileVersion.Version;
389 // If neither [AssemblyInformationalVersionAttribute]
390 // nor [AssemblyFileVersion] are present, then use
391 // the assembly version
392 if (version == null || version.Length == 0)
393 version = assembly.GetName ().Version.ToString ();
399 public static string SafeTopLevelCaptionFormat {
401 return safe_caption_format;
404 safe_caption_format = value;
408 public static string StartupPath {
410 return Path.GetDirectoryName (Application.ExecutablePath);
414 public static string UserAppDataPath {
416 return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData));
420 public static RegistryKey UserAppDataRegistry {
422 string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
424 return Registry.CurrentUser.CreateSubKey (key);
428 public static bool UseWaitCursor {
430 return use_wait_cursor;
433 use_wait_cursor = value;
434 if (use_wait_cursor) {
435 foreach (Form form in OpenForms) {
436 form.Cursor = Cursors.WaitCursor;
442 public static bool RenderWithVisualStyles {
444 if (VisualStyleInformation.IsSupportedByOS) {
445 if (!VisualStyleInformation.IsEnabledByUser)
447 if (!XplatUI.ThemesEnabled)
449 if (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled)
451 if (Application.VisualStyleState == VisualStyleState.ClientAreaEnabled)
458 public static VisualStyleState VisualStyleState {
459 get { return Application.visual_style_state; }
460 set { Application.visual_style_state = value; }
465 #region Public Static Methods
467 public static void AddMessageFilter (IMessageFilter value)
469 lock (message_filters) {
470 message_filters.Add (value);
474 internal static void AddKeyFilter (IKeyFilter value)
476 XplatUI.AddKeyFilter (value);
479 public static void DoEvents ()
484 public static void EnableVisualStyles ()
486 visual_styles_enabled = true;
487 XplatUI.EnableThemes ();
490 [EditorBrowsable (EditorBrowsableState.Advanced)]
491 public static bool FilterMessage (ref Message message)
493 lock (message_filters) {
494 for (int i = 0; i < message_filters.Count; i++) {
495 IMessageFilter filter = (IMessageFilter) message_filters[i];
496 if (filter.PreFilterMessage (ref message))
504 // If true, it uses GDI+, performance reasons were quoted
506 static internal bool use_compatible_text_rendering = true;
508 public static void SetCompatibleTextRenderingDefault (bool defaultValue)
510 use_compatible_text_rendering = defaultValue;
513 public static FormCollection OpenForms {
519 [MonoNotSupported ("Only applies when Winforms is being hosted by an unmanaged app.")]
520 [EditorBrowsable (EditorBrowsableState.Advanced)]
521 public static void RegisterMessageLoop (MessageLoopCallback callback)
525 [MonoNotSupported ("Empty stub.")]
526 public static bool SetSuspendState (PowerState state, bool force, bool disableWakeEvent)
531 [MonoNotSupported ("Empty stub.")]
532 public static void SetUnhandledExceptionMode (UnhandledExceptionMode mode)
534 //FIXME: a stub to fill
537 [MonoNotSupported ("Empty stub.")]
538 public static void SetUnhandledExceptionMode (UnhandledExceptionMode mode, bool threadScope)
540 //FIXME: a stub to fill
543 [MonoNotSupported ("Only applies when Winforms is being hosted by an unmanaged app.")]
544 [EditorBrowsable (EditorBrowsableState.Advanced)]
545 public static void UnregisterMessageLoop ()
549 [EditorBrowsable (EditorBrowsableState.Advanced)]
550 public static void RaiseIdle (EventArgs e)
552 XplatUI.RaiseIdle (e);
555 public static void Restart ()
557 //FIXME: ClickOnce stuff using the Update or UpdateAsync methods.
558 //FIXME: SecurityPermission: Restart () requires IsUnrestricted permission.
560 if (Assembly.GetEntryAssembly () == null)
561 throw new NotSupportedException ("The method 'Restart' is not supported by this application type.");
563 string mono_path = null;
566 PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static | BindingFlags.NonPublic);
567 MethodInfo get_gac = null;
569 get_gac = gac.GetGetMethod (true);
571 if (get_gac != null) {
572 string gac_path = Path.GetDirectoryName ((string)get_gac.Invoke (null, null));
573 string mono_prefix = Path.GetDirectoryName (Path.GetDirectoryName (gac_path));
575 if (XplatUI.RunningOnUnix) {
576 mono_path = Path.Combine (mono_prefix, "bin/mono");
577 if (!File.Exists (mono_path))
580 mono_path = Path.Combine (mono_prefix, "bin\\mono.bat");
582 if (!File.Exists (mono_path))
583 mono_path = Path.Combine (mono_prefix, "bin\\mono.exe");
585 if (!File.Exists (mono_path))
586 mono_path = Path.Combine (mono_prefix, "mono\\mono\\mini\\mono.exe");
588 if (!File.Exists (mono_path))
589 throw new FileNotFoundException (string.Format ("Windows mono path not found: '{0}'", mono_path));
593 //Get command line arguments
594 StringBuilder argsBuilder = new StringBuilder ();
595 string[] args = Environment.GetCommandLineArgs ();
596 for (int i = 0; i < args.Length; i++)
598 argsBuilder.Append (string.Format ("\"{0}\" ", args[i]));
600 string arguments = argsBuilder.ToString ();
601 ProcessStartInfo procInfo = Process.GetCurrentProcess ().StartInfo;
603 if (mono_path == null) { //it is .NET on Windows
604 procInfo.FileName = args[0];
605 procInfo.Arguments = arguments.Remove (0, args[0].Length + 3); //1 space and 2 quotes
608 procInfo.Arguments = arguments;
609 procInfo.FileName = mono_path;
612 procInfo.WorkingDirectory = Environment.CurrentDirectory;
615 Process.Start (procInfo);
618 public static void Exit ()
620 Exit (new CancelEventArgs ());
623 [EditorBrowsable (EditorBrowsableState.Advanced)]
624 public static void Exit (CancelEventArgs e)
626 ArrayList forms_to_close;
629 forms_to_close = new ArrayList (forms);
631 foreach (Form f in forms_to_close) {
632 // Give each form a chance to cancel the Application.Exit
633 e.Cancel = f.FireClosingEvents (CloseReason.ApplicationExitCall, false);
638 f.suppress_closing_events = true;
644 XplatUI.PostQuitMessage (0);
647 public static void ExitThread()
649 CloseForms(Thread.CurrentThread);
650 // this might not be right - need to investigate (somehow) if a WM_QUIT message is generated here
651 XplatUI.PostQuitMessage(0);
654 public static ApartmentState OleRequired ()
656 //throw new NotImplementedException("OLE Not supported by this System.Windows.Forms implementation");
657 return ApartmentState.Unknown;
660 public static void OnThreadException (Exception t)
662 if (MWFThread.Current.HandlingException) {
663 /* we're already handling an exception and we got
664 another one? print it out and exit, this means
665 we've got a runtime/SWF bug. */
666 Console.WriteLine (t);
667 // Don't use Application.Exit here, since it may cause a stack overflow
668 // in certain cases. It's however hard to reproduce since it seems to
669 // be depending on when the GC kicks in.
674 MWFThread.Current.HandlingException = true;
676 if (Application.ThreadException != null) {
677 Application.ThreadException(null, new ThreadExceptionEventArgs(t));
681 if (SystemInformation.UserInteractive) {
682 Form form = new ThreadExceptionDialog (t);
685 Console.WriteLine (t.ToString ());
689 MWFThread.Current.HandlingException = false;
693 public static void RemoveMessageFilter (IMessageFilter value)
695 lock (message_filters) {
696 message_filters.Remove (value);
700 public static void Run ()
702 Run (new ApplicationContext ());
705 public static void Run (Form mainForm)
707 Run (new ApplicationContext (mainForm));
710 internal static void FirePreRun ()
712 EventHandler handler = PreRun;
714 handler (null, EventArgs.Empty);
717 public static void Run (ApplicationContext context)
719 // If a sync context hasn't been created by now, create
721 if (SynchronizationContext.Current == null)
722 SynchronizationContext.SetSynchronizationContext (new SynchronizationContext ());
724 RunLoop (false, context);
726 // Reset the sync context back to the default
727 if (SynchronizationContext.Current is WindowsFormsSynchronizationContext)
728 WindowsFormsSynchronizationContext.Uninstall ();
731 private static void DisableFormsForModalLoop (Queue toplevels, ApplicationContext context)
736 IEnumerator control = forms.GetEnumerator ();
738 while (control.MoveNext ()) {
739 f = (Form)control.Current;
741 // Don't disable the main form.
742 if (f == context.MainForm) {
746 // Don't disable any children of the main form.
747 // These do not have to be MDI children.
749 bool is_child_of_main = false; ;
752 if (current.Parent == context.MainForm) {
753 is_child_of_main = true;
756 current = current.Parent;
757 } while (current != null);
759 if (is_child_of_main)
763 if (f.IsHandleCreated && XplatUI.IsEnabled (f.Handle)) {
765 Console.WriteLine(" Disabling form {0}", f);
767 XplatUI.EnableWindow (f.Handle, false);
768 toplevels.Enqueue (f);
776 private static void EnableFormsForModalLoop (Queue toplevels, ApplicationContext context)
778 while (toplevels.Count > 0) {
780 Console.WriteLine(" Re-Enabling form form {0}", toplevels.Peek());
782 Form c = (Form) toplevels.Dequeue ();
783 if (c.IsHandleCreated) {
784 XplatUI.EnableWindow (c.window.Handle, true);
785 context.MainForm = c;
789 Console.WriteLine(" Done with the re-enable");
793 internal static void RunLoop (bool Modal, ApplicationContext context)
799 ApplicationContext previous_thread_context;
801 thread = MWFThread.Current;
804 * There is a NotWorking test for this, but since we are using this method both for Form.ShowDialog as for ApplicationContexts we'll
805 * fail on nested ShowDialogs, so disable the check for the moment.
807 //if (thread.MessageLoop) {
808 // throw new InvalidOperationException ("Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.");
814 context = new ApplicationContext();
816 previous_thread_context = thread.Context;
817 thread.Context = context;
819 if (context.MainForm != null) {
820 context.MainForm.is_modal = Modal;
821 context.MainForm.context = context;
822 context.MainForm.closing = false;
823 context.MainForm.Visible = true; // Cannot use Show() or scaling gets confused by menus
824 // XXX the above line can be used to close the form. another problem with our handling of Show/Activate.
825 if (context.MainForm != null)
826 context.MainForm.Activate();
830 Console.WriteLine("Entering RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
834 toplevels = new Queue ();
835 DisableFormsForModalLoop (toplevels, context);
837 // FIXME - need activate?
838 /* make sure the MainForm is enabled */
839 if (context.MainForm != null) {
840 XplatUI.EnableWindow (context.MainForm.Handle, true);
841 XplatUI.SetModal(context.MainForm.Handle, true);
847 queue_id = XplatUI.StartLoop(Thread.CurrentThread);
848 thread.MessageLoop = true;
852 while (!quit && XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0)) {
853 Message m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
855 if (Application.FilterMessage (ref m))
858 switch((Msg)msg.message) {
860 case Msg.WM_SYSKEYDOWN:
864 case Msg.WM_SYSKEYUP:
866 c = Control.FromHandle(msg.hwnd);
868 // If we have a control with keyboard capture (usually a *Strip)
869 // give it the message, and then drop the message
870 if (keyboard_capture != null) {
871 // WM_SYSKEYUP does not make it into ProcessCmdKey, so do it here
872 if ((Msg)m.Msg == Msg.WM_SYSKEYDOWN)
873 if (m.WParam.ToInt32() == (int)Keys.Menu) {
874 keyboard_capture.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.Keyboard);
878 m.HWnd = keyboard_capture.Handle;
880 switch (keyboard_capture.PreProcessControlMessageInternal (ref m)) {
881 case PreProcessControlState.MessageProcessed:
883 case PreProcessControlState.MessageNeeded:
884 case PreProcessControlState.MessageNotNeeded:
885 if (((m.Msg == (int)Msg.WM_KEYDOWN || m.Msg == (int)Msg.WM_CHAR) && !keyboard_capture.ProcessControlMnemonic ((char)m.WParam))) {
886 if (c == null || !ControlOnToolStrip (c))
897 if (((c != null) && c.PreProcessControlMessageInternal (ref m) != PreProcessControlState.MessageProcessed) ||
903 case Msg.WM_LBUTTONDOWN:
904 case Msg.WM_MBUTTONDOWN:
905 case Msg.WM_RBUTTONDOWN:
906 if (keyboard_capture != null) {
907 Control c2 = Control.FromHandle (msg.hwnd);
909 // the target is not a winforms control (an embedded control, perhaps), so
910 // release everything
912 ToolStripManager.FireAppClicked ();
916 // If we clicked a ToolStrip, we have to make sure it isn't
917 // the one we are on, or any of its parents or children
918 // If we clicked off the dropped down menu, release everything
919 if (c2 is ToolStrip) {
920 if ((c2 as ToolStrip).GetTopLevelToolStrip () != keyboard_capture.GetTopLevelToolStrip ())
921 ToolStripManager.FireAppClicked ();
923 if (c2.Parent != null)
924 if (c2.Parent is ToolStripDropDownMenu)
925 if ((c2.Parent as ToolStripDropDownMenu).GetTopLevelToolStrip () == keyboard_capture.GetTopLevelToolStrip ())
927 if (c2.TopLevelControl == null)
930 ToolStripManager.FireAppClicked ();
937 quit = true; // make sure we exit
940 XplatUI.TranslateMessage (ref msg);
941 XplatUI.DispatchMessage (ref msg);
945 // If our Form doesn't have a handle anymore, it means it was destroyed and we need to *wait* for WM_QUIT.
946 if ((context.MainForm != null) && (!context.MainForm.IsHandleCreated))
949 // Handle exit, Form might have received WM_CLOSE and set 'closing' in response.
950 if ((context.MainForm != null) && (context.MainForm.closing || (Modal && !context.MainForm.Visible))) {
952 XplatUI.PostQuitMessage (0);
959 Console.WriteLine (" RunLoop loop left");
962 thread.MessageLoop = false;
963 XplatUI.EndLoop (Thread.CurrentThread);
966 Form old = context.MainForm;
968 context.MainForm = null;
970 EnableFormsForModalLoop (toplevels, context);
972 if (context.MainForm != null && context.MainForm.IsHandleCreated) {
973 XplatUI.SetModal (context.MainForm.Handle, false);
976 Console.WriteLine (" Done with the SetModal");
978 old.RaiseCloseEvents (true, false);
979 old.is_modal = false;
983 Console.WriteLine ("Leaving RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
986 if (context.MainForm != null) {
987 context.MainForm.context = null;
988 context.MainForm = null;
991 thread.Context = previous_thread_context;
997 #endregion // Public Static Methods
1001 public static event EventHandler ApplicationExit;
1003 public static event EventHandler Idle {
1005 XplatUI.Idle += value;
1008 XplatUI.Idle -= value;
1012 public static event EventHandler ThreadExit;
1013 public static event ThreadExceptionEventHandler ThreadException;
1015 // These are used externally by the UIA framework
1016 internal static event EventHandler FormAdded;
1017 internal static event EventHandler PreRun;
1019 #pragma warning disable 0067
1021 [EditorBrowsable (EditorBrowsableState.Advanced)]
1022 public static event EventHandler EnterThreadModal;
1025 [EditorBrowsable (EditorBrowsableState.Advanced)]
1026 public static event EventHandler LeaveThreadModal;
1027 #pragma warning restore 0067
1029 #endregion // Events
1031 #region Public Delegates
1033 [EditorBrowsable (EditorBrowsableState.Advanced)]
1034 public delegate bool MessageLoopCallback ();
1038 #region Internal Properties
1039 internal static ToolStrip KeyboardCapture {
1040 get { return keyboard_capture; }
1041 set { keyboard_capture = value; }
1044 internal static bool VisualStylesEnabled {
1045 get { return visual_styles_enabled; }
1049 #region Internal Methods
1051 internal static void AddForm (Form f)
1055 // Signal that a Form has been added to this
1056 // Application. Used by UIA to detect new Forms that
1057 // need a11y support. This event may be fired even if
1058 // the form has already been added, so clients should
1059 // account for that when handling this signal.
1060 if (FormAdded != null)
1061 FormAdded (f, null);
1064 internal static void RemoveForm (Form f)
1070 private static bool ControlOnToolStrip (Control c)
1072 Control p = c.Parent;
1084 // Takes a starting path, appends company name, product name, and
1085 // product version. If the directory doesn't exist, create it
1086 private static string CreateDataPath (string basePath)
1090 path = Path.Combine (basePath, CompanyName);
1091 path = Path.Combine (path, ProductName);
1092 path = Path.Combine (path, ProductVersion);
1094 if (!Directory.Exists (path))
1095 Directory.CreateDirectory (path);