// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-// Copyright (c) 2004 Novell, Inc.
+// Copyright (c) 2004 - 2006 Novell, Inc.
//
// Authors:
// Peter Bartok pbartok@novell.com
//
-
// COMPLETE
+#undef DebugRunLoop
+
using Microsoft.Win32;
using System;
using System.Drawing;
namespace System.Windows.Forms {
public sealed class Application {
- private static bool browser_embedded = false;
- private static bool exiting = false;
- private static InputLanguage input_language = InputLanguage.CurrentInputLanguage;
- private static bool messageloop_started = false;
- private static string safe_caption_format = "{1} - {0} - {2}";
- private static ArrayList message_filters = new ArrayList();
- private static ApplicationContext app_context = null;
+ private class MWFThread {
+ #region Fields
+ private ApplicationContext context;
+ private bool messageloop_started;
+ private int thread_id;
- private Application () {
- }
+ private static Hashtable threads = new Hashtable();
+ #endregion // Fields
- #region Private and Internal Methods
- internal static void ModalRun(Form form) {
- MSG msg = new MSG();
- Queue toplevels = new Queue();
- IEnumerator control = Control.controls.GetEnumerator();
+ #region Constructors
+ private MWFThread() {
+ }
+ #endregion // Constructors
- if (form == null) {
- return;
+ #region Properties
+ public ApplicationContext Context {
+ get {
+ return context;
+ }
+
+ set {
+ context = value;
+ }
}
- // Both calls are needed, one is for the WM, the other for our focus logic
- XplatUI.Activate(form.window.Handle);
- form.Activate();
+ public bool MessageLoop {
+ get {
+ return messageloop_started;
+ }
- while (control.MoveNext()) {
- if ((((Control)control.Current).parent == null) && (((Control)control.Current).is_visible) && (((Control)control.Current).is_enabled)) {
- if ((control.Current is Form) && (((Form)control.Current)!=form)) {
- XplatUI.EnableWindow(((Control)control.Current).window.Handle, false);
- toplevels.Enqueue((Control)control.Current);
- }
+ set {
+ messageloop_started = value;
}
}
- form.CreateControl();
- while (!exiting && !form.end_modal && XplatUI.GetMessage(ref msg, IntPtr.Zero, 0, 0)) {
- if ((message_filters != null) && (message_filters.Count > 0)) {
- Message m;
- bool drop;
+ public static int LoopCount {
+ get {
+ IEnumerator e;
+ int loops;
+ MWFThread thread;
- drop = false;
- m = new Message();
- m.Msg = (int)msg.message;
- m.HWnd = msg.hwnd;
- m.LParam = msg.lParam;
- m.WParam = msg.wParam;
- for (int i = 0; i < message_filters.Count; i++) {
- if (((IMessageFilter)message_filters[i]).PreFilterMessage(ref m)) {
- // we're dropping the message
- drop = true;
- break;
+ e = threads.Values.GetEnumerator();
+ loops = 0;
+
+ while (e.MoveNext()) {
+ thread = (MWFThread)e.Current;
+ if (thread != null && thread.messageloop_started) {
+ loops++;
}
}
- if (drop) {
- continue;
+
+ return loops;
+ }
+ }
+
+ public static MWFThread Current {
+ get {
+ MWFThread thread;
+
+ thread = null;
+ lock (threads) {
+ thread = (MWFThread)threads[Thread.CurrentThread.GetHashCode()];
+ if (thread == null) {
+ thread = new MWFThread();
+ thread.thread_id = Thread.CurrentThread.GetHashCode();
+ threads[thread.thread_id] = thread;
+ }
}
+
+ return thread;
}
+ }
+ #endregion // Properties
- XplatUI.TranslateMessage(ref msg);
- XplatUI.DispatchMessage(ref msg);
+ #region Methods
+ public void Exit() {
+ if (context != null) {
+ context.ExitThread();
+ }
+ context = null;
- // Handle exit, Form might have received WM_CLOSE and set 'closing' in response
- if (form.closing) {
- form.end_modal = true;
+ if (Application.ThreadExit != null) {
+ Application.ThreadExit(null, EventArgs.Empty);
}
+
+ if (LoopCount == 0) {
+ if (Application.ApplicationExit != null) {
+ Application.ApplicationExit(null, EventArgs.Empty);
+ }
+ }
+ threads[thread_id] = null;
}
+ #endregion // Methods
+ }
- while (toplevels.Count>0) {
- XplatUI.EnableWindow(((Control)toplevels.Dequeue()).window.Handle, true);
+ private static bool browser_embedded = false;
+ private static InputLanguage input_language = InputLanguage.CurrentInputLanguage;
+ private static string safe_caption_format = "{1} - {0} - {2}";
+ private static ArrayList message_filters = new ArrayList();
+
+ private Application () {
+ }
+
+ #region Private Methods
+ private static void CloseForms(Thread thread) {
+ Control c;
+ IEnumerator control;
+ bool all;
+
+ #if DebugRunLoop
+ Console.WriteLine(" CloseForms({0}) called", thread);
+ #endif
+ if (thread == null) {
+ all = true;
+ } else {
+ all = false;
+ }
+
+ control = Control.controls.GetEnumerator();
+
+ while (control.MoveNext()) {
+ c = (Control)control.Current;
+ if (c is Form) {
+ if (all || (thread == c.creator_thread)) {
+ if (c.IsHandleCreated) {
+ XplatUI.PostMessage(c.Handle, Msg.WM_CLOSE_INTERNAL, IntPtr.Zero, IntPtr.Zero);
+ }
+ #if DebugRunLoop
+ Console.WriteLine(" Closing form {0}", c);
+ #endif
+ }
+ }
}
+
}
- #endregion // Private and Internal Methods
+ #endregion // Private methods
#region Public Static Properties
public static bool AllowQuit {
public static bool MessageLoop {
get {
- return messageloop_started;
+ return MWFThread.Current.MessageLoop;
}
}
}
#if NET_2_0
- public static void EnableRTLMirroring ()
+ //
+ // If true, it uses GDI+, performance reasons were quoted
+ //
+ static internal bool use_compatible_text_rendering = true;
+
+ public static void SetCompatibleTextRenderingDefault (bool defaultValue)
{
+ use_compatible_text_rendering = defaultValue;
}
#endif
public static void Exit() {
- XplatUI.Exit();
- }
+ CloseForms(null);
- public static void ExitThread() {
- exiting=true;
+ // FIXME - this needs to be fired when they're all closed
+ // But CloseForms uses PostMessage, so it gets fired before
+ // We need to wait on something...
+ if (ApplicationExit != null) {
+ ApplicationExit(null, EventArgs.Empty);
+ }
}
- private static void InternalExit(object sender, EventArgs e) {
- Application.Exit();
+ public static void ExitThread() {
+ CloseForms(Thread.CurrentThread);
+ MWFThread.Current.Exit();
}
public static ApartmentState OleRequired() {
Application.ThreadException(null, new ThreadExceptionEventArgs(t));
return;
}
-#if !later
- else {
- XplatUI.HandleException(t);
- }
-#else
- // TODO: Missing implementation
- //if (SystemInformation.UserInteractive)
- {
+
+ if (SystemInformation.UserInteractive) {
Form form = new ThreadExceptionDialog (t);
form.ShowDialog ();
- }
- //else
+ } else {
Console.WriteLine (t.ToString ());
-#endif
+ }
}
public static void RemoveMessageFilter(IMessageFilter filter) {
}
public static void Run() {
- MSG msg = new MSG();
- Form form = null;
+ RunLoop(false, new ApplicationContext());
+ }
+
+ public static void Run(Form mainForm) {
+ RunLoop(false, new ApplicationContext(mainForm));
+ }
+
+ public static void Run(ApplicationContext context) {
+ RunLoop(false, context);
+ }
+
+ internal static void RunLoop(bool Modal, ApplicationContext context) {
+ Queue toplevels;
+ IEnumerator control;
+ MSG msg;
+ Object queue_id;
+ MWFThread thread;
+
+
+ thread = MWFThread.Current;
- if (app_context != null) {
- form = app_context.MainForm;
+ msg = new MSG();
+
+ if (context == null) {
+ context = new ApplicationContext();
}
- if (form != null) {
- // Both calls are needed, one is for the WM, the other for our focus logic
- XplatUI.Activate(form.window.Handle);
- form.Activate();
+ thread.Context = context;
+
+ if (context.MainForm != null) {
+ context.MainForm.is_modal = Modal;
+ context.MainForm.context = context;
+ context.MainForm.closing = false;
+ context.MainForm.Visible = true; // Cannot use Show() or scaling gets confused by menus
+ // FIXME - do we need this?
+ //context.MainForm.PerformLayout();
+ context.MainForm.Activate();
}
- messageloop_started = true;
+ #if DebugRunLoop
+ Console.WriteLine("Entering RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
+ #endif
+
+ if (Modal) {
+ Control c;
- while (!exiting && XplatUI.GetMessage(ref msg, IntPtr.Zero, 0, 0)) {
+ toplevels = new Queue();
+ control = Control.controls.GetEnumerator();
+
+ while (control.MoveNext()) {
+
+ c = (Control)control.Current;
+ if (c is Form && (c != context.MainForm)) {
+ if (c.IsHandleCreated && XplatUI.IsEnabled(c.Handle)) {
+ #if DebugRunLoop
+ Console.WriteLine(" Disabling form {0}", c);
+ #endif
+ XplatUI.EnableWindow(c.Handle, false);
+ toplevels.Enqueue(c);
+ }
+ }
+ }
+ // FIXME - need activate?
+
+ XplatUI.SetModal(context.MainForm.Handle, true);
+ } else {
+ toplevels = null;
+ }
+
+ queue_id = XplatUI.StartLoop(Thread.CurrentThread);
+ thread.MessageLoop = true;
+
+ while (XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0)) {
if ((message_filters != null) && (message_filters.Count > 0)) {
Message m;
bool drop;
drop = false;
- m = new Message();
- m.Msg = (int)msg.message;
- m.HWnd = msg.hwnd;
- m.LParam = msg.lParam;
- m.WParam = msg.wParam;
+ m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
for (int i = 0; i < message_filters.Count; i++) {
if (((IMessageFilter)message_filters[i]).PreFilterMessage(ref m)) {
// we're dropping the message
}
}
- XplatUI.TranslateMessage(ref msg);
- XplatUI.DispatchMessage(ref msg);
+ switch((Msg)msg.message) {
+ case Msg.WM_KEYDOWN:
+ case Msg.WM_SYSKEYDOWN:
+ case Msg.WM_CHAR:
+ case Msg.WM_SYSCHAR:
+ case Msg.WM_KEYUP:
+ case Msg.WM_SYSKEYUP: {
+ Message m;
+ Control c;
+
+ m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
+ c = Control.FromHandle(msg.hwnd);
+ if ((c != null) && !c.PreProcessMessage(ref m)) {
+ goto default;
+ }
+ break;
+ }
+ default: {
+ XplatUI.TranslateMessage(ref msg);
+ XplatUI.DispatchMessage(ref msg);
+ break;
+ }
+ }
// Handle exit, Form might have received WM_CLOSE and set 'closing' in response
- if ((form != null) && form.closing) {
- exiting = true;
+ if ((context.MainForm != null) && (context.MainForm.closing || (Modal && !context.MainForm.Visible))) {
+ if (!Modal) {
+ XplatUI.PostQuitMessage(0);
+ } else {
+ break;
+ }
}
}
+ #if DebugRunLoop
+ Console.WriteLine(" RunLoop loop left");
+ #endif
- messageloop_started = false;
+ thread.MessageLoop = false;
+ XplatUI.EndLoop(Thread.CurrentThread);
- if (ThreadExit != null) {
- ThreadExit(null, EventArgs.Empty);
- }
+ if (Modal) {
+ Control c;
- if (ApplicationExit != null) {
- ApplicationExit(null, EventArgs.Empty);
+ context.MainForm.Hide();
+ context.MainForm.is_modal = false;
+
+ while (toplevels.Count>0) {
+ #if DebugRunLoop
+ Console.WriteLine(" Re-Enabling form form {0}", toplevels.Peek());
+ #endif
+ c = (Control)toplevels.Dequeue();
+ if (c.IsHandleCreated) {
+ XplatUI.EnableWindow(c.window.Handle, true);
+ }
+ }
+ #if DebugRunLoop
+ Console.WriteLine(" Done with the re-enable");
+ #endif
+ if (context.MainForm.IsHandleCreated) {
+ XplatUI.SetModal(context.MainForm.Handle, false);
+ }
+ #if DebugRunLoop
+ Console.WriteLine(" Done with the SetModal");
+ #endif
}
- }
- public static void Run(Form mainForm) {
- mainForm.CreateControl();
- Run(new ApplicationContext(mainForm));
- }
+ #if DebugRunLoop
+ Console.WriteLine("Leaving RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
+ #endif
+ if (context.MainForm != null) {
+ context.MainForm.context = null;
+ }
- public static void Run(ApplicationContext context) {
- app_context=context;
- if (app_context.MainForm!=null) {
- app_context.MainForm.Show();
- app_context.MainForm.PerformLayout();
- app_context.ThreadExit += new EventHandler(InternalExit);
+ if (!Modal) {
+ thread.Exit();
}
- Run();
}
+
#endregion // Public Static Methods
#region Events