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 = MonoToolsLocator.Mono;
565 //Get command line arguments
566 StringBuilder argsBuilder = new StringBuilder ();
567 string[] args = Environment.GetCommandLineArgs ();
568 for (int i = 0; i < args.Length; i++)
570 argsBuilder.Append (string.Format ("\"{0}\" ", args[i]));
572 string arguments = argsBuilder.ToString ();
573 ProcessStartInfo procInfo = Process.GetCurrentProcess ().StartInfo;
575 if (mono_path == null) { //it is .NET on Windows
576 procInfo.FileName = args[0];
577 procInfo.Arguments = arguments.Remove (0, args[0].Length + 3); //1 space and 2 quotes
580 procInfo.Arguments = arguments;
581 procInfo.FileName = mono_path;
584 procInfo.WorkingDirectory = Environment.CurrentDirectory;
587 Process.Start (procInfo);
590 public static void Exit ()
592 Exit (new CancelEventArgs ());
595 [EditorBrowsable (EditorBrowsableState.Advanced)]
596 public static void Exit (CancelEventArgs e)
598 ArrayList forms_to_close;
601 forms_to_close = new ArrayList (forms);
603 foreach (Form f in forms_to_close) {
604 // Give each form a chance to cancel the Application.Exit
605 e.Cancel = f.FireClosingEvents (CloseReason.ApplicationExitCall, false);
610 f.suppress_closing_events = true;
616 XplatUI.PostQuitMessage (0);
619 public static void ExitThread()
621 CloseForms(Thread.CurrentThread);
622 // this might not be right - need to investigate (somehow) if a WM_QUIT message is generated here
623 XplatUI.PostQuitMessage(0);
626 public static ApartmentState OleRequired ()
628 //throw new NotImplementedException("OLE Not supported by this System.Windows.Forms implementation");
629 return ApartmentState.Unknown;
632 public static void OnThreadException (Exception t)
634 if (MWFThread.Current.HandlingException) {
635 /* we're already handling an exception and we got
636 another one? print it out and exit, this means
637 we've got a runtime/SWF bug. */
638 Console.WriteLine (t);
639 // Don't use Application.Exit here, since it may cause a stack overflow
640 // in certain cases. It's however hard to reproduce since it seems to
641 // be depending on when the GC kicks in.
646 MWFThread.Current.HandlingException = true;
648 if (Application.ThreadException != null) {
649 Application.ThreadException(null, new ThreadExceptionEventArgs(t));
653 if (SystemInformation.UserInteractive) {
654 Form form = new ThreadExceptionDialog (t);
657 Console.WriteLine (t.ToString ());
661 MWFThread.Current.HandlingException = false;
665 public static void RemoveMessageFilter (IMessageFilter value)
667 lock (message_filters) {
668 message_filters.Remove (value);
672 public static void Run ()
674 Run (new ApplicationContext ());
677 public static void Run (Form mainForm)
679 Run (new ApplicationContext (mainForm));
682 internal static void FirePreRun ()
684 EventHandler handler = PreRun;
686 handler (null, EventArgs.Empty);
689 public static void Run (ApplicationContext context)
691 // If a sync context hasn't been created by now, create
693 if (SynchronizationContext.Current == null)
694 SynchronizationContext.SetSynchronizationContext (new SynchronizationContext ());
696 RunLoop (false, context);
698 // Reset the sync context back to the default
699 if (SynchronizationContext.Current is WindowsFormsSynchronizationContext)
700 WindowsFormsSynchronizationContext.Uninstall ();
703 private static void DisableFormsForModalLoop (Queue toplevels, ApplicationContext context)
708 IEnumerator control = forms.GetEnumerator ();
710 while (control.MoveNext ()) {
711 f = (Form)control.Current;
713 // Don't disable the main form.
714 if (f == context.MainForm) {
718 // Don't disable any children of the main form.
719 // These do not have to be MDI children.
721 bool is_child_of_main = false; ;
724 if (current.Parent == context.MainForm) {
725 is_child_of_main = true;
728 current = current.Parent;
729 } while (current != null);
731 if (is_child_of_main)
735 if (f.IsHandleCreated && XplatUI.IsEnabled (f.Handle)) {
737 Console.WriteLine(" Disabling form {0}", f);
739 XplatUI.EnableWindow (f.Handle, false);
740 toplevels.Enqueue (f);
748 private static void EnableFormsForModalLoop (Queue toplevels, ApplicationContext context)
750 while (toplevels.Count > 0) {
752 Console.WriteLine(" Re-Enabling form form {0}", toplevels.Peek());
754 Form c = (Form) toplevels.Dequeue ();
755 if (c.IsHandleCreated) {
756 XplatUI.EnableWindow (c.window.Handle, true);
757 context.MainForm = c;
761 Console.WriteLine(" Done with the re-enable");
765 internal static void RunLoop (bool Modal, ApplicationContext context)
771 ApplicationContext previous_thread_context;
773 thread = MWFThread.Current;
776 * There is a NotWorking test for this, but since we are using this method both for Form.ShowDialog as for ApplicationContexts we'll
777 * fail on nested ShowDialogs, so disable the check for the moment.
779 //if (thread.MessageLoop) {
780 // throw new InvalidOperationException ("Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.");
786 context = new ApplicationContext();
788 previous_thread_context = thread.Context;
789 thread.Context = context;
791 if (context.MainForm != null) {
792 context.MainForm.is_modal = Modal;
793 context.MainForm.context = context;
794 context.MainForm.closing = false;
795 context.MainForm.Visible = true; // Cannot use Show() or scaling gets confused by menus
796 // XXX the above line can be used to close the form. another problem with our handling of Show/Activate.
797 if (context.MainForm != null)
798 context.MainForm.Activate();
802 Console.WriteLine("Entering RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
806 toplevels = new Queue ();
807 DisableFormsForModalLoop (toplevels, context);
809 // FIXME - need activate?
810 /* make sure the MainForm is enabled */
811 if (context.MainForm != null) {
812 XplatUI.EnableWindow (context.MainForm.Handle, true);
813 XplatUI.SetModal(context.MainForm.Handle, true);
819 queue_id = XplatUI.StartLoop(Thread.CurrentThread);
820 thread.MessageLoop = true;
824 while (!quit && XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0)) {
825 Message m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
827 if (Application.FilterMessage (ref m))
830 switch((Msg)msg.message) {
832 case Msg.WM_SYSKEYDOWN:
836 case Msg.WM_SYSKEYUP:
838 c = Control.FromHandle(msg.hwnd);
840 // If we have a control with keyboard capture (usually a *Strip)
841 // give it the message, and then drop the message
842 if (keyboard_capture != null) {
843 // WM_SYSKEYUP does not make it into ProcessCmdKey, so do it here
844 if ((Msg)m.Msg == Msg.WM_SYSKEYDOWN)
845 if (m.WParam.ToInt32() == (int)Keys.Menu) {
846 keyboard_capture.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.Keyboard);
850 m.HWnd = keyboard_capture.Handle;
852 switch (keyboard_capture.PreProcessControlMessageInternal (ref m)) {
853 case PreProcessControlState.MessageProcessed:
855 case PreProcessControlState.MessageNeeded:
856 case PreProcessControlState.MessageNotNeeded:
857 if (((m.Msg == (int)Msg.WM_KEYDOWN || m.Msg == (int)Msg.WM_CHAR) && !keyboard_capture.ProcessControlMnemonic ((char)m.WParam))) {
858 if (c == null || !ControlOnToolStrip (c))
869 if (((c != null) && c.PreProcessControlMessageInternal (ref m) != PreProcessControlState.MessageProcessed) ||
875 case Msg.WM_LBUTTONDOWN:
876 case Msg.WM_MBUTTONDOWN:
877 case Msg.WM_RBUTTONDOWN:
878 if (keyboard_capture != null) {
879 Control c2 = Control.FromHandle (msg.hwnd);
881 // the target is not a winforms control (an embedded control, perhaps), so
882 // release everything
884 ToolStripManager.FireAppClicked ();
888 // If we clicked a ToolStrip, we have to make sure it isn't
889 // the one we are on, or any of its parents or children
890 // If we clicked off the dropped down menu, release everything
891 if (c2 is ToolStrip) {
892 if ((c2 as ToolStrip).GetTopLevelToolStrip () != keyboard_capture.GetTopLevelToolStrip ())
893 ToolStripManager.FireAppClicked ();
895 if (c2.Parent != null)
896 if (c2.Parent is ToolStripDropDownMenu)
897 if ((c2.Parent as ToolStripDropDownMenu).GetTopLevelToolStrip () == keyboard_capture.GetTopLevelToolStrip ())
899 if (c2.TopLevelControl == null)
902 ToolStripManager.FireAppClicked ();
909 quit = true; // make sure we exit
912 XplatUI.TranslateMessage (ref msg);
913 XplatUI.DispatchMessage (ref msg);
917 // If our Form doesn't have a handle anymore, it means it was destroyed and we need to *wait* for WM_QUIT.
918 if ((context.MainForm != null) && (!context.MainForm.IsHandleCreated))
921 // Handle exit, Form might have received WM_CLOSE and set 'closing' in response.
922 if ((context.MainForm != null) && (context.MainForm.closing || (Modal && !context.MainForm.Visible))) {
924 XplatUI.PostQuitMessage (0);
931 Console.WriteLine (" RunLoop loop left");
934 thread.MessageLoop = false;
935 XplatUI.EndLoop (Thread.CurrentThread);
938 Form old = context.MainForm;
940 context.MainForm = null;
942 EnableFormsForModalLoop (toplevels, context);
944 if (old != null && old.IsHandleCreated) {
945 XplatUI.SetModal (old.Handle, false);
948 Console.WriteLine (" Done with the SetModal");
950 old.RaiseCloseEvents (true, false);
951 old.is_modal = false;
955 Console.WriteLine ("Leaving RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
958 if (context.MainForm != null) {
959 context.MainForm.context = null;
960 context.MainForm = null;
963 thread.Context = previous_thread_context;
969 #endregion // Public Static Methods
973 public static event EventHandler ApplicationExit;
975 public static event EventHandler Idle {
977 XplatUI.Idle += value;
980 XplatUI.Idle -= value;
984 public static event EventHandler ThreadExit;
985 public static event ThreadExceptionEventHandler ThreadException;
987 // These are used externally by the UIA framework
988 internal static event EventHandler FormAdded;
989 internal static event EventHandler PreRun;
991 #pragma warning disable 0067
993 [EditorBrowsable (EditorBrowsableState.Advanced)]
994 public static event EventHandler EnterThreadModal;
997 [EditorBrowsable (EditorBrowsableState.Advanced)]
998 public static event EventHandler LeaveThreadModal;
999 #pragma warning restore 0067
1001 #endregion // Events
1003 #region Public Delegates
1005 [EditorBrowsable (EditorBrowsableState.Advanced)]
1006 public delegate bool MessageLoopCallback ();
1010 #region Internal Properties
1011 internal static ToolStrip KeyboardCapture {
1012 get { return keyboard_capture; }
1013 set { keyboard_capture = value; }
1016 internal static bool VisualStylesEnabled {
1017 get { return visual_styles_enabled; }
1021 #region Internal Methods
1023 internal static void AddForm (Form f)
1027 // Signal that a Form has been added to this
1028 // Application. Used by UIA to detect new Forms that
1029 // need a11y support. This event may be fired even if
1030 // the form has already been added, so clients should
1031 // account for that when handling this signal.
1032 if (FormAdded != null)
1033 FormAdded (f, null);
1036 internal static void RemoveForm (Form f)
1042 private static bool ControlOnToolStrip (Control c)
1044 Control p = c.Parent;
1056 // Takes a starting path, appends company name, product name, and
1057 // product version. If the directory doesn't exist, create it
1058 private static string CreateDataPath (string basePath)
1062 path = Path.Combine (basePath, CompanyName);
1063 path = Path.Combine (path, ProductName);
1064 path = Path.Combine (path, ProductVersion);
1066 if (!Directory.Exists (path))
1067 Directory.CreateDirectory (path);