using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
-#if NET_2_0
using System.Text;
using System.Windows.Forms.VisualStyles;
-#endif
namespace System.Windows.Forms
{
private static readonly ArrayList message_filters = new ArrayList();
private static readonly FormCollection forms = new FormCollection ();
-#if NET_2_0
private static bool use_wait_cursor;
private static ToolStrip keyboard_capture;
private static VisualStyleState visual_style_state = VisualStyleState.ClientAndNonClientAreasEnabled;
-#endif
+ static bool visual_styles_enabled;
private Application ()
{
+ browser_embedded = false;
+ }
+
+ static Application ()
+ {
+ // Attempt to load UIA support for winforms
+ // UIA support requires .NET 2.0
+ InitializeUIAutomation ();
}
#region Private Methods
+ private static void InitializeUIAutomation ()
+ {
+ // Initialize the UIAutomationWinforms Global class,
+ // which create some listeners which subscribe to internal
+ // MWF events so that it can provide a11y support for MWF
+ const string UIA_WINFORMS_ASSEMBLY =
+ "UIAutomationWinforms, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f4ceacb585d99812";
+ MethodInfo init_method;
+ Assembly mwf_providers = null;
+ try {
+ mwf_providers = Assembly.Load (UIA_WINFORMS_ASSEMBLY);
+ } catch { }
+
+ if (mwf_providers == null)
+ return;
+
+ const string UIA_WINFORMS_TYPE = "Mono.UIAutomation.Winforms.Global";
+ const string UIA_WINFORMS_METHOD = "Initialize";
+ try {
+ Type global_type = mwf_providers.GetType (UIA_WINFORMS_TYPE, false);
+ if (global_type != null) {
+ init_method = global_type.GetMethod (UIA_WINFORMS_METHOD,
+ BindingFlags.Static |
+ BindingFlags.Public);
+ if (init_method != null)
+ init_method.Invoke (null, new object [] {});
+ else
+ throw new Exception (String.Format ("Method {0} not found in type {1}.",
+ UIA_WINFORMS_METHOD, UIA_WINFORMS_TYPE));
+ }
+ else
+ throw new Exception (String.Format ("Type {0} not found in assembly {1}.",
+ UIA_WINFORMS_TYPE, UIA_WINFORMS_ASSEMBLY));
+ } catch (Exception ex) {
+ Console.Error.WriteLine ("Error setting up UIA: " + ex);
+ }
+ }
+
internal static void CloseForms (Thread thread)
{
#if DebugRunLoop
public static string CommonAppDataPath {
get {
- return Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData);
+ return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData));
}
}
public static RegistryKey CommonAppDataRegistry {
get {
- return Registry.LocalMachine.OpenSubKey ("Software\\" +
- Application.CompanyName + "\\" + Application.ProductName +
- "\\" + Application.ProductVersion, true);
+ string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
+
+ return Registry.LocalMachine.CreateSubKey (key);
}
}
public static string CompanyName {
get {
+ string company = string.Empty;
+
Assembly assembly = Assembly.GetEntryAssembly ();
+
if (assembly == null)
assembly = Assembly.GetCallingAssembly ();
AssemblyCompanyAttribute[] attrs = (AssemblyCompanyAttribute[])
assembly.GetCustomAttributes (typeof(AssemblyCompanyAttribute), true);
if (attrs != null && attrs.Length > 0)
- return attrs [0].Company;
+ company = attrs [0].Company;
+
+ // If there is no [AssemblyCompany], return the outermost namespace
+ // on Main ()
+ if (company == null || company.Length == 0)
+ if (assembly.EntryPoint != null) {
+ company = assembly.EntryPoint.DeclaringType.Namespace;
+
+ if (company != null) {
+ int firstDot = company.IndexOf ('.');
+ if (firstDot >= 0)
+ company = company.Substring (0, firstDot);
+ }
+ }
- return assembly.GetName().Name;
+ // If that doesn't work, return the name of class containing Main ()
+ if (company == null || company.Length == 0)
+ if (assembly.EntryPoint != null)
+ company = assembly.EntryPoint.DeclaringType.FullName;
+
+ return company;
}
}
public static string ExecutablePath {
get {
- return Assembly.GetEntryAssembly().Location;
+ return Path.GetFullPath (Environment.GetCommandLineArgs ()[0]);
}
}
public static string LocalUserAppDataPath {
get {
- return Path.Combine (Path.Combine (Path.Combine (
- Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData),
- CompanyName), ProductName), ProductVersion);
+ return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData));
}
}
public static string ProductName {
get {
+ string name = string.Empty;
+
Assembly assembly = Assembly.GetEntryAssembly ();
+
if (assembly == null)
assembly = Assembly.GetCallingAssembly ();
AssemblyProductAttribute[] attrs = (AssemblyProductAttribute[])
- assembly.GetCustomAttributes(typeof(AssemblyProductAttribute), true);
+ assembly.GetCustomAttributes (typeof(AssemblyProductAttribute), true);
if (attrs != null && attrs.Length > 0)
- return attrs [0].Product;
+ name = attrs [0].Product;
+
+ // If there is no [AssemblyProduct], .NET returns the name of
+ // the innermost namespace and if that fails, resorts to the
+ // name of the class containing Main ()
+ if (name == null || name.Length == 0)
+ if (assembly.EntryPoint != null) {
+ name = assembly.EntryPoint.DeclaringType.Namespace;
+
+ if (name != null) {
+ int lastDot = name.LastIndexOf ('.');
+ if (lastDot >= 0 && lastDot < name.Length - 1)
+ name = name.Substring (lastDot + 1);
+ }
+
+ if (name == null || name.Length == 0)
+ name = assembly.EntryPoint.DeclaringType.FullName;
+ }
- return assembly.GetName ().Name;
+ return name;
}
}
public static string ProductVersion {
get {
- String version;
+ String version = string.Empty;
Assembly assembly = Assembly.GetEntryAssembly ();
+
if (assembly == null)
assembly = Assembly.GetCallingAssembly ();
Attribute.GetCustomAttribute (assembly,
typeof (AssemblyInformationalVersionAttribute))
as AssemblyInformationalVersionAttribute;
+
if (infoVersion != null)
version = infoVersion.InformationalVersion;
- else
+
+ // If [AssemblyFileVersion] is present it is used
+ // before resorting to assembly version
+ if (version == null || version.Length == 0) {
+ AssemblyFileVersionAttribute fileVersion =
+ Attribute.GetCustomAttribute (assembly,
+ typeof (AssemblyFileVersionAttribute))
+ as AssemblyFileVersionAttribute;
+ if (fileVersion != null)
+ version = fileVersion.Version;
+ }
+
+ // If neither [AssemblyInformationalVersionAttribute]
+ // nor [AssemblyFileVersion] are present, then use
+ // the assembly version
+ if (version == null || version.Length == 0)
version = assembly.GetName ().Version.ToString ();
+
return version;
}
}
public static string UserAppDataPath {
get {
- return Path.Combine (Path.Combine (Path.Combine (
- Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
- CompanyName), ProductName), ProductVersion);
+ return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData));
}
}
public static RegistryKey UserAppDataRegistry {
get {
- return Registry.CurrentUser.OpenSubKey ("Software\\" +
- Application.CompanyName + "\\" + Application.ProductName +
- "\\" + Application.ProductVersion, true);
+ string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion);
+
+ return Registry.CurrentUser.CreateSubKey (key);
}
}
-#if NET_2_0
public static bool UseWaitCursor {
get {
return use_wait_cursor;
}
}
}
-
+
public static bool RenderWithVisualStyles {
get {
if (VisualStyleInformation.IsSupportedByOS) {
get { return Application.visual_style_state; }
set { Application.visual_style_state = value; }
}
-#endif
#endregion
}
}
+ internal static void AddKeyFilter (IKeyFilter value)
+ {
+ XplatUI.AddKeyFilter (value);
+ }
+
public static void DoEvents ()
{
XplatUI.DoEvents ();
public static void EnableVisualStyles ()
{
+ visual_styles_enabled = true;
XplatUI.EnableThemes ();
}
-#if NET_2_0
[EditorBrowsable (EditorBrowsableState.Advanced)]
- public
-#endif
- static bool FilterMessage (ref Message message)
+ public static bool FilterMessage (ref Message message)
{
- lock (message_filters)
- foreach (IMessageFilter filter in message_filters)
+ lock (message_filters) {
+ for (int i = 0; i < message_filters.Count; i++) {
+ IMessageFilter filter = (IMessageFilter) message_filters[i];
if (filter.PreFilterMessage (ref message))
return true;
-
+ }
+ }
return false;
}
-#if NET_2_0
//
// If true, it uses GDI+, performance reasons were quoted
//
Application.Exit ();
Process.Start (procInfo);
}
-#endif
public static void Exit ()
{
- XplatUI.PostQuitMessage (0);
- CloseForms (null);
+ Exit (new CancelEventArgs ());
}
-#if NET_2_0
[EditorBrowsable (EditorBrowsableState.Advanced)]
public static void Exit (CancelEventArgs e)
{
foreach (Form f in forms_to_close) {
// Give each form a chance to cancel the Application.Exit
- e.Cancel = f.FireClosingEvents (CloseReason.ApplicationExitCall);
+ e.Cancel = f.FireClosingEvents (CloseReason.ApplicationExitCall, false);
if (e.Cancel)
return;
+ f.suppress_closing_events = true;
f.Close ();
f.Dispose ();
}
XplatUI.PostQuitMessage (0);
}
-#endif
public static void ExitThread()
{
}
}
- public static void RemoveMessageFilter (IMessageFilter filter)
+ public static void RemoveMessageFilter (IMessageFilter value)
{
lock (message_filters) {
- message_filters.Remove (filter);
+ message_filters.Remove (value);
}
}
public static void Run ()
{
- RunLoop (false, new ApplicationContext ());
+ Run (new ApplicationContext ());
}
public static void Run (Form mainForm)
{
- RunLoop (false, new ApplicationContext (mainForm));
+ Run (new ApplicationContext (mainForm));
+ }
+
+ internal static void FirePreRun ()
+ {
+ EventHandler handler = PreRun;
+ if (handler != null)
+ handler (null, EventArgs.Empty);
}
public static void Run (ApplicationContext context)
{
+ // If a sync context hasn't been created by now, create
+ // a default one
+ if (SynchronizationContext.Current == null)
+ SynchronizationContext.SetSynchronizationContext (new SynchronizationContext ());
+
RunLoop (false, context);
+
+ // Reset the sync context back to the default
+ if (SynchronizationContext.Current is WindowsFormsSynchronizationContext)
+ WindowsFormsSynchronizationContext.Uninstall ();
}
private static void DisableFormsForModalLoop (Queue toplevels, ApplicationContext context)
Control c;
c = Control.FromHandle(msg.hwnd);
-#if NET_2_0
// If we have a control with keyboard capture (usually a *Strip)
// give it the message, and then drop the message
if (keyboard_capture != null) {
// WM_SYSKEYUP does not make it into ProcessCmdKey, so do it here
- if ((Msg)m.Msg == Msg.WM_SYSKEYUP)
+ if ((Msg)m.Msg == Msg.WM_SYSKEYDOWN)
if (m.WParam.ToInt32() == (int)Keys.Menu) {
keyboard_capture.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.Keyboard);
continue;
}
m.HWnd = keyboard_capture.Handle;
-
- if (keyboard_capture.PreProcessControlMessageInternal (ref m) != PreProcessControlState.MessageProcessed && (m.Msg == (int)Msg.WM_KEYDOWN && !keyboard_capture.ProcessControlMnemonic ((char)m.WParam))) {
- if (c == null || c.Parent == null || !(c.Parent is ToolStrip))
+
+ switch (keyboard_capture.PreProcessControlMessageInternal (ref m)) {
+ case PreProcessControlState.MessageProcessed:
continue;
- else
- m.HWnd = msg.hwnd;
- } else
- continue;
+ case PreProcessControlState.MessageNeeded:
+ case PreProcessControlState.MessageNotNeeded:
+ if (((m.Msg == (int)Msg.WM_KEYDOWN || m.Msg == (int)Msg.WM_CHAR) && !keyboard_capture.ProcessControlMnemonic ((char)m.WParam))) {
+ if (c == null || !ControlOnToolStrip (c))
+ continue;
+ else
+ m.HWnd = msg.hwnd;
+ } else
+ continue;
+
+ break;
+ }
}
-#endif
- if ((c != null) && c.PreProcessControlMessageInternal (ref m) != PreProcessControlState.MessageProcessed) {
+ if (((c != null) && c.PreProcessControlMessageInternal (ref m) != PreProcessControlState.MessageProcessed) ||
+ (c == null)) {
goto default;
- }
+ }
break;
-#if NET_2_0
+
case Msg.WM_LBUTTONDOWN:
case Msg.WM_MBUTTONDOWN:
case Msg.WM_RBUTTONDOWN:
if (keyboard_capture != null) {
Control c2 = Control.FromHandle (msg.hwnd);
-
+
+ // the target is not a winforms control (an embedded control, perhaps), so
+ // release everything
+ if (c2 == null) {
+ ToolStripManager.FireAppClicked ();
+ goto default;
+ }
+
// If we clicked a ToolStrip, we have to make sure it isn't
// the one we are on, or any of its parents or children
// If we clicked off the dropped down menu, release everything
if (c2 is ToolStrip) {
if ((c2 as ToolStrip).GetTopLevelToolStrip () != keyboard_capture.GetTopLevelToolStrip ())
ToolStripManager.FireAppClicked ();
- } else
+ } else {
+ if (c2.Parent != null)
+ if (c2.Parent is ToolStripDropDownMenu)
+ if ((c2.Parent as ToolStripDropDownMenu).GetTopLevelToolStrip () == keyboard_capture.GetTopLevelToolStrip ())
+ goto default;
+ if (c2.TopLevelControl == null)
+ goto default;
+
ToolStripManager.FireAppClicked ();
+ }
}
goto default;
-#endif
+
case Msg.WM_QUIT:
quit = true; // make sure we exit
break;
break;
}
- // Handle exit, Form might have received WM_CLOSE and set 'closing' in response
+ // If our Form doesn't have a handle anymore, it means it was destroyed and we need to *wait* for WM_QUIT.
+ if ((context.MainForm != null) && (!context.MainForm.IsHandleCreated))
+ continue;
+
+ // Handle exit, Form might have received WM_CLOSE and set 'closing' in response.
if ((context.MainForm != null) && (context.MainForm.closing || (Modal && !context.MainForm.Visible))) {
if (!Modal) {
XplatUI.PostQuitMessage (0);
#if DebugRunLoop
Console.WriteLine (" Done with the SetModal");
#endif
- old.RaiseCloseEvents (true);
+ old.RaiseCloseEvents (true, false);
old.is_modal = false;
}
public static event EventHandler ThreadExit;
public static event ThreadExceptionEventHandler ThreadException;
+
+ // These are used externally by the UIA framework
+ internal static event EventHandler FormAdded;
+ internal static event EventHandler PreRun;
-#if NET_2_0
+#pragma warning disable 0067
+ [MonoTODO]
[EditorBrowsable (EditorBrowsableState.Advanced)]
public static event EventHandler EnterThreadModal;
+ [MonoTODO]
[EditorBrowsable (EditorBrowsableState.Advanced)]
public static event EventHandler LeaveThreadModal;
-#endif
+#pragma warning restore 0067
#endregion // Events
#region Public Delegates
-#if NET_2_0
[EditorBrowsable (EditorBrowsableState.Advanced)]
public delegate bool MessageLoopCallback ();
-#endif
#endregion
#region Internal Properties
-#if NET_2_0
internal static ToolStrip KeyboardCapture {
get { return keyboard_capture; }
set { keyboard_capture = value; }
}
-#endif
+
+ internal static bool VisualStylesEnabled {
+ get { return visual_styles_enabled; }
+ }
#endregion
#region Internal Methods
{
lock (forms)
forms.Add (f);
+ // Signal that a Form has been added to this
+ // Application. Used by UIA to detect new Forms that
+ // need a11y support. This event may be fired even if
+ // the form has already been added, so clients should
+ // account for that when handling this signal.
+ if (FormAdded != null)
+ FormAdded (f, null);
}
internal static void RemoveForm (Form f)
forms.Remove (f);
}
+ private static bool ControlOnToolStrip (Control c)
+ {
+ Control p = c.Parent;
+
+ while (p != null) {
+ if (p is ToolStrip)
+ return true;
+
+ p = p.Parent;
+ }
+
+ return false;
+ }
+
+ // Takes a starting path, appends company name, product name, and
+ // product version. If the directory doesn't exist, create it
+ private static string CreateDataPath (string basePath)
+ {
+ string path;
+
+ path = Path.Combine (basePath, CompanyName);
+ path = Path.Combine (path, ProductName);
+ path = Path.Combine (path, ProductVersion);
+
+ if (!Directory.Exists (path))
+ Directory.CreateDirectory (path);
+
+ return path;
+ }
#endregion
}
}