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
30 using Microsoft.Win32;
33 using System.ComponentModel;
34 using System.Collections;
35 using System.Diagnostics;
36 using System.Globalization;
38 using System.Reflection;
39 using System.Runtime.InteropServices;
40 using System.Threading;
42 namespace System.Windows.Forms {
43 public sealed class Application {
44 private class MWFThread {
46 private ApplicationContext context;
47 private bool messageloop_started;
48 private int thread_id;
50 private static Hashtable threads = new Hashtable();
56 #endregion // Constructors
59 public ApplicationContext Context {
69 public bool MessageLoop {
71 return messageloop_started;
75 messageloop_started = value;
80 public static int LoopCount {
86 e = threads.Values.GetEnumerator();
89 while (e.MoveNext()) {
90 thread = (MWFThread)e.Current;
91 if (thread != null && thread.messageloop_started) {
100 public static MWFThread Current {
106 thread = (MWFThread)threads[Thread.CurrentThread.GetHashCode()];
107 if (thread == null) {
108 thread = new MWFThread();
109 thread.thread_id = Thread.CurrentThread.GetHashCode();
110 threads[thread.thread_id] = thread;
117 #endregion // Properties
121 if (context != null) {
122 context.ExitThread();
126 if (Application.ThreadExit != null) {
127 Application.ThreadExit(null, EventArgs.Empty);
130 if (LoopCount == 0) {
131 if (Application.ApplicationExit != null) {
132 Application.ApplicationExit(null, EventArgs.Empty);
135 threads[thread_id] = null;
137 #endregion // Methods
140 private static bool browser_embedded = false;
141 private static InputLanguage input_language = InputLanguage.CurrentInputLanguage;
142 private static string safe_caption_format = "{1} - {0} - {2}";
143 private static ArrayList message_filters = new ArrayList();
145 private Application () {
148 #region Private Methods
149 private static void CloseForms(Thread thread) {
155 Console.WriteLine(" CloseForms({0}) called", thread);
157 if (thread == null) {
163 control = Control.controls.GetEnumerator();
165 while (control.MoveNext()) {
166 c = (Control)control.Current;
168 if (all || (thread == c.creator_thread)) {
169 if (c.IsHandleCreated) {
170 XplatUI.PostMessage(c.Handle, Msg.WM_CLOSE_INTERNAL, IntPtr.Zero, IntPtr.Zero);
173 Console.WriteLine(" Closing form {0}", c);
180 #endregion // Private methods
182 #region Public Static Properties
183 public static bool AllowQuit {
185 return browser_embedded;
189 public static string CommonAppDataPath {
191 return Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
195 public static RegistryKey CommonAppDataRegistry {
199 key = Registry.LocalMachine.OpenSubKey("Software\\" + Application.CompanyName + "\\" + Application.ProductName + "\\" + Application.ProductVersion, true);
205 public static string CompanyName {
207 AssemblyCompanyAttribute[] attrs = (AssemblyCompanyAttribute[]) Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), true);
209 if ((attrs != null) && attrs.Length>0) {
210 return attrs[0].Company;
213 return Assembly.GetEntryAssembly().GetName().Name;
217 public static CultureInfo CurrentCulture {
219 return Thread.CurrentThread.CurrentUICulture;
224 Thread.CurrentThread.CurrentUICulture=value;
228 public static InputLanguage CurrentInputLanguage {
230 return input_language;
234 input_language=value;
238 public static string ExecutablePath {
240 return Assembly.GetEntryAssembly().Location;
244 public static string LocalUserAppDataPath {
246 return Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), CompanyName), ProductName), ProductVersion);
250 public static bool MessageLoop {
252 return MWFThread.Current.MessageLoop;
256 public static string ProductName {
258 AssemblyProductAttribute[] attrs = (AssemblyProductAttribute[]) Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true);
260 if ((attrs != null) && attrs.Length>0) {
261 return attrs[0].Product;
264 return Assembly.GetEntryAssembly().GetName().Name;
268 public static string ProductVersion {
272 version = Assembly.GetEntryAssembly().GetName().Version.ToString();
274 if (version.StartsWith("0.")) {
275 version="1." + version.Substring(2);
281 public static string SafeTopLevelCaptionFormat {
283 return safe_caption_format;
287 safe_caption_format=value;
291 public static string StartupPath {
293 return Path.GetDirectoryName(Application.ExecutablePath);
297 public static string UserAppDataPath {
299 return Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), CompanyName), ProductName), ProductVersion);
303 public static RegistryKey UserAppDataRegistry {
307 key = Registry.CurrentUser.OpenSubKey("Software\\" + Application.CompanyName + "\\" + Application.ProductName + "\\" + Application.ProductVersion, true);
314 #region Public Static Methods
315 public static void AddMessageFilter(IMessageFilter value) {
316 message_filters.Add(value);
319 public static void DoEvents() {
323 public static void EnableVisualStyles() {
324 XplatUI.EnableThemes();
329 // If true, it uses GDI+, performance reasons were quoted
331 static internal bool use_compatible_text_rendering = true;
333 public static void SetCompatibleTextRenderingDefault (bool defaultValue)
335 use_compatible_text_rendering = defaultValue;
339 public static void Exit() {
342 // FIXME - this needs to be fired when they're all closed
343 // But CloseForms uses PostMessage, so it gets fired before
344 // We need to wait on something...
345 if (ApplicationExit != null) {
346 ApplicationExit(null, EventArgs.Empty);
350 public static void ExitThread() {
351 CloseForms(Thread.CurrentThread);
352 MWFThread.Current.Exit();
355 public static ApartmentState OleRequired() {
356 //throw new NotImplementedException("OLE Not supported by this System.Windows.Forms implementation");
357 return ApartmentState.Unknown;
360 public static void OnThreadException(Exception t) {
361 if (Application.ThreadException != null) {
362 Application.ThreadException(null, new ThreadExceptionEventArgs(t));
366 if (SystemInformation.UserInteractive) {
367 Form form = new ThreadExceptionDialog (t);
370 Console.WriteLine (t.ToString ());
374 public static void RemoveMessageFilter(IMessageFilter filter) {
375 message_filters.Remove(filter);
378 public static void Run() {
379 RunLoop(false, new ApplicationContext());
382 public static void Run(Form mainForm) {
383 RunLoop(false, new ApplicationContext(mainForm));
386 public static void Run(ApplicationContext context) {
387 RunLoop(false, context);
390 internal static void RunLoop(bool Modal, ApplicationContext context) {
398 thread = MWFThread.Current;
402 if (context == null) {
403 context = new ApplicationContext();
406 thread.Context = context;
408 if (context.MainForm != null) {
409 context.MainForm.Visible = true; // Cannot use Show() or scaling gets confused by menus
410 // FIXME - do we need this?
411 //context.MainForm.PerformLayout();
412 context.MainForm.context = context;
413 context.MainForm.Activate();
414 context.MainForm.closing = false;
418 Console.WriteLine("Entering RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
424 if (context.MainForm.Modal) {
425 throw new Exception("fixme");
427 context.MainForm.is_modal = true;
429 toplevels = new Queue();
430 control = Control.controls.GetEnumerator();
432 while (control.MoveNext()) {
434 c = (Control)control.Current;
435 if (c is Form && (c != context.MainForm)) {
436 if (c.IsHandleCreated && XplatUI.IsEnabled(c.Handle)) {
438 Console.WriteLine(" Disabling form {0}", c);
440 XplatUI.EnableWindow(c.Handle, false);
441 toplevels.Enqueue(c);
445 // FIXME - need activate?
447 XplatUI.SetModal(context.MainForm.Handle, true);
452 queue_id = XplatUI.StartLoop(Thread.CurrentThread);
453 thread.MessageLoop = true;
455 while (XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0)) {
456 if ((message_filters != null) && (message_filters.Count > 0)) {
461 m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
462 for (int i = 0; i < message_filters.Count; i++) {
463 if (((IMessageFilter)message_filters[i]).PreFilterMessage(ref m)) {
464 // we're dropping the message
474 switch((Msg)msg.message) {
476 case Msg.WM_SYSKEYDOWN:
480 case Msg.WM_SYSKEYUP: {
484 m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
485 c = Control.FromHandle(msg.hwnd);
486 if ((c != null) && !c.PreProcessMessage(ref m)) {
492 XplatUI.TranslateMessage(ref msg);
493 XplatUI.DispatchMessage(ref msg);
498 // Handle exit, Form might have received WM_CLOSE and set 'closing' in response
499 if ((context.MainForm != null) && context.MainForm.closing) {
501 XplatUI.PostQuitMessage(0);
508 Console.WriteLine(" RunLoop loop left");
511 thread.MessageLoop = false;
512 XplatUI.EndLoop(Thread.CurrentThread);
517 context.MainForm.Hide();
518 context.MainForm.is_modal = false;
520 while (toplevels.Count>0) {
522 Console.WriteLine(" Re-Enabling form form {0}", toplevels.Peek());
524 c = (Control)toplevels.Dequeue();
525 if (c.IsHandleCreated) {
526 XplatUI.EnableWindow(c.window.Handle, true);
530 Console.WriteLine(" Done with the re-enable");
532 if (context.MainForm.IsHandleCreated) {
533 XplatUI.SetModal(context.MainForm.Handle, false);
536 Console.WriteLine(" Done with the SetModal");
541 Console.WriteLine("Leaving RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL");
543 if (context.MainForm != null) {
544 context.MainForm.context = null;
552 #endregion // Public Static Methods
555 public static event EventHandler ApplicationExit;
557 public static event EventHandler Idle {
559 XplatUI.Idle += value;
562 XplatUI.Idle -= value;
566 public static event EventHandler ThreadExit;
567 public static event ThreadExceptionEventHandler ThreadException;