Author: toshok
Date: 2007-02-28 16:31:26 -0500 (Wed, 28 Feb 2007)
New Revision: 73571
Modified:
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/Application.cs
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/ApplicationContext.cs
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs
branches/mwf-handle-branch/Managed.Windows.Forms/Test/System.Windows.Forms/ChangeLog
branches/mwf-handle-branch/Managed.Windows.Forms/Test/System.Windows.Forms/ControlTest.cs
Log:
In Test/System.Windows.Forms:
2007-02-28 Chris Toshok <[EMAIL PROTECTED]>
* ControlTest.cs: Flesh out ControlInvokeTest to make sure that
the Control thread dies (that Application.Run returns, basically).
This works in isolation, but for some reason it isn't exiting when
run in concert with other tests (this test is the cause of the
hangs running the unit tests.) Marking NotWorking for the time
being. This needs to be fixed before merging back to the
mainline, imo.
In System.Windows.Forms:
2007-02-28 Chris Toshok <[EMAIL PROTECTED]>
* ApplicationContext.cs: Add a flag to make sure we only raise the
ThreadExit event once (ExitThreadCore can be indirectly called
from a few places.) I don't like the additional flag, but it
makes the event ordering/count correct.
* Application.cs (MWFThread.LoopCount): don't use an enumerator
without locking the collection. An enumerator doesn't give us any
protection from modification anyway. Lock the thread hash and
replace the complicated enumerator loop with a foreach.
(Application.CloseForms): make internal so it can be called from
ApplicationContext. This should probably be moved to MWFThread.
(Application.ExitThread): don't call MWFThread.Current.Exit()
here. just call XplatUI.PostQuitMessage. We'll exit the thread
when the runloop exits (in response to WM_QUIT.)
(Application.RunLoop): add a comment (and check) for
context.MainForm being null after setting context.MainForm.Visible
= true. This is because you're perfectly free to dispose of a
form in VisibilityChanged. Chalk this up to another case where we
need to synchronously generate WM_ACTIVATE from Control.Show.
Also, add handling for WM_QUIT here so we'll exit the loop.
* XplatUIX11.cs: clean up MapWindow and UnmapWindow a bit. The
fact that we don't wait if we're only unmapping the whole_window
makes me a bit nervous, but it doesn't seem to cause any problems
yet.
also, add a comment about the stupid, broken and wrong resetting
of PostQuitState to false in GetMessage().
In PostQuitMessage, we need to add a WM_QUIT message to the
thread's queue. We use the FosterParent to get the right
handle/hwnd/queue.
Lastly, in SetVisible, we need to unmap both windows, since the
waiting only happens when we're unmapping the client window. So
now, the *only* time we unmap just the whole_window is in the hack
for resizing a control to 0,0.
Modified:
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/Application.cs
===================================================================
---
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/Application.cs
2007-02-28 21:05:20 UTC (rev 73570)
+++
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/Application.cs
2007-02-28 21:31:26 UTC (rev 73571)
@@ -80,21 +80,16 @@
public static int LoopCount {
get {
- IEnumerator e;
- int loops;
- MWFThread thread;
+ lock (threads) {
+ int loops = 0;
- e = threads.Values.GetEnumerator();
- loops = 0;
-
- while (e.MoveNext()) {
- thread = (MWFThread)e.Current;
- if (thread != null &&
thread.messageloop_started) {
- loops++;
+ foreach (MWFThread thread in
threads.Values) {
+ if
(thread.messageloop_started)
+ loops++;
}
- }
- return loops;
+ return loops;
+ }
}
}
@@ -133,9 +128,8 @@
Application.ApplicationExit(null, EventArgs.Empty);
}
}
- lock (threads) {
- threads[thread_id] = null;
- }
+
+ ((MWFThread)threads[thread_id]).MessageLoop =
false;
}
#endregion // Methods
}
@@ -155,7 +149,7 @@
}
#region Private Methods
- private static void CloseForms(Thread thread) {
+ internal static void CloseForms(Thread thread) {
#if DebugRunLoop
Console.WriteLine(" CloseForms({0}) called",
thread);
#endif
@@ -449,19 +443,14 @@
#endif
public static void Exit() {
+ XplatUI.PostQuitMessage(0);
CloseForms(null);
-
- // 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);
- }
}
public static void ExitThread() {
CloseForms(Thread.CurrentThread);
- MWFThread.Current.Exit();
+ // this might not be right - need to investigate
(somehow) if a WM_QUIT message is generated here
+ XplatUI.PostQuitMessage(0);
}
public static ApartmentState OleRequired() {
@@ -537,9 +526,9 @@
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();
+ // XXX the above line can be used to close the
form. another problem with our handling of Show/Activate.
+ if (context.MainForm != null)
+ context.MainForm.Activate();
}
#if DebugRunLoop
@@ -582,7 +571,9 @@
queue_id = XplatUI.StartLoop(Thread.CurrentThread);
thread.MessageLoop = true;
- while (XplatUI.GetMessage(queue_id, ref msg,
IntPtr.Zero, 0, 0)) {
+ bool quit = false;
+
+ while (!quit && XplatUI.GetMessage(queue_id, ref msg,
IntPtr.Zero, 0, 0)) {
lock (message_filters) {
if (message_filters.Count > 0) {
Message m;
@@ -619,6 +610,9 @@
goto default;
}
break;
+ case Msg.WM_QUIT:
+ quit = true; // make sure we exit
+ break;
default:
XplatUI.TranslateMessage(ref msg);
XplatUI.DispatchMessage(ref msg);
Modified:
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/ApplicationContext.cs
===================================================================
---
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/ApplicationContext.cs
2007-02-28 21:05:20 UTC (rev 73570)
+++
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/ApplicationContext.cs
2007-02-28 21:31:26 UTC (rev 73571)
@@ -36,6 +36,8 @@
#if NET_2_0
object tag;
#endif
+ bool thread_exit_raised;
+
#endregion // Local Variables
#region Public Constructors & Destructors
@@ -104,7 +106,9 @@
}
protected virtual void ExitThreadCore() {
- if (ThreadExit!=null) {
+ XplatUI.PostQuitMessage(0);
+ if (!thread_exit_raised && ThreadExit != null) {
+ thread_exit_raised = true;
ThreadExit(this, EventArgs.Empty);
}
}
Modified:
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
===================================================================
---
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
2007-02-28 21:05:20 UTC (rev 73570)
+++
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
2007-02-28 21:31:26 UTC (rev 73571)
@@ -1,3 +1,43 @@
+2007-02-28 Chris Toshok <[EMAIL PROTECTED]>
+
+ * ApplicationContext.cs: Add a flag to make sure we only raise the
+ ThreadExit event once (ExitThreadCore can be indirectly called
+ from a few places.) I don't like the additional flag, but it
+ makes the event ordering/count correct.
+
+ * Application.cs (MWFThread.LoopCount): don't use an enumerator
+ without locking the collection. An enumerator doesn't give us any
+ protection from modification anyway. Lock the thread hash and
+ replace the complicated enumerator loop with a foreach.
+ (Application.CloseForms): make internal so it can be called from
+ ApplicationContext. This should probably be moved to MWFThread.
+ (Application.ExitThread): don't call MWFThread.Current.Exit()
+ here. just call XplatUI.PostQuitMessage. We'll exit the thread
+ when the runloop exits (in response to WM_QUIT.)
+ (Application.RunLoop): add a comment (and check) for
+ context.MainForm being null after setting context.MainForm.Visible
+ = true. This is because you're perfectly free to dispose of a
+ form in VisibilityChanged. Chalk this up to another case where we
+ need to synchronously generate WM_ACTIVATE from Control.Show.
+ Also, add handling for WM_QUIT here so we'll exit the loop.
+
+ * XplatUIX11.cs: clean up MapWindow and UnmapWindow a bit. The
+ fact that we don't wait if we're only unmapping the whole_window
+ makes me a bit nervous, but it doesn't seem to cause any problems
+ yet.
+
+ also, add a comment about the stupid, broken and wrong resetting
+ of PostQuitState to false in GetMessage().
+
+ In PostQuitMessage, we need to add a WM_QUIT message to the
+ thread's queue. We use the FosterParent to get the right
+ handle/hwnd/queue.
+
+ Lastly, in SetVisible, we need to unmap both windows, since the
+ waiting only happens when we're unmapping the client window. So
+ now, the *only* time we unmap just the whole_window is in the hack
+ for resizing a control to 0,0.
+
2007-02-21 Chris Toshok <[EMAIL PROTECTED]>
* Application.cs (CloseForms): rewrite this so that we don't
Modified:
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs
===================================================================
---
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs
2007-02-28 21:05:20 UTC (rev 73570)
+++
branches/mwf-handle-branch/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs
2007-02-28 21:31:26 UTC (rev 73571)
@@ -1292,31 +1292,41 @@
private void MapWindow(Hwnd hwnd, WindowType windows) {
if (!hwnd.mapped) {
- hwnd.mapped = true;
+ bool need_to_wait = false;
+
if ((windows & WindowType.Whole) != 0) {
XMapWindow(DisplayHandle,
hwnd.whole_window);
}
if ((windows & WindowType.Client) != 0) {
XMapWindow(DisplayHandle,
hwnd.client_window);
- if (Control.FromHandle(hwnd.Handle) is
Form)
- WaitForHwndMessage (hwnd,
Msg.WM_SHOWWINDOW);
+ need_to_wait = true;
}
+
+ hwnd.mapped = true;
+
+ if (need_to_wait &&
Control.FromHandle(hwnd.Handle) is Form)
+ WaitForHwndMessage (hwnd,
Msg.WM_SHOWWINDOW);
}
}
private void UnmapWindow(Hwnd hwnd, WindowType windows) {
if (hwnd.mapped) {
- hwnd.mapped = false;
+ bool need_to_wait = false;
+
+ if ((windows & WindowType.Client) != 0) {
+ XUnmapWindow(DisplayHandle,
hwnd.client_window);
+
+ need_to_wait = true;
+ }
if ((windows & WindowType.Whole) != 0) {
XUnmapWindow(DisplayHandle,
hwnd.whole_window);
}
- if ((windows & WindowType.Client) != 0) {
- XUnmapWindow(DisplayHandle,
hwnd.client_window);
- if (Control.FromHandle(hwnd.Handle) is
Form)
- WaitForHwndMessage (hwnd,
Msg.WM_SHOWWINDOW);
- }
+ hwnd.mapped = false;
+
+ if (need_to_wait &&
Control.FromHandle(hwnd.Handle) is Form)
+ WaitForHwndMessage (hwnd,
Msg.WM_SHOWWINDOW);
}
}
@@ -3269,6 +3279,14 @@
}
// We reset ourselves so GetMessage can
be called again
+
+ // XXX this is *so* wrong. if
+ // we've posted the quit
+ // message we shouldn't *be*
+ // called again. Removing it,
+ // however, makes many of the
+ // ListView unit tests fail.
+ // should investigate why.
ThreadQueue(Thread.CurrentThread).PostQuitState = false;
return false;
@@ -4293,7 +4311,7 @@
}
internal override void PostQuitMessage(int exitCode) {
-
+ PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero,
IntPtr.Zero);
XFlush(DisplayHandle);
ThreadQueue(Thread.CurrentThread).PostQuitState = true;
}
@@ -4858,7 +4876,7 @@
SendMessage(handle,
Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
}
else {
- UnmapWindow(hwnd, WindowType.Whole);
+ UnmapWindow(hwnd, WindowType.Both);
}
}
return true;
Modified:
branches/mwf-handle-branch/Managed.Windows.Forms/Test/System.Windows.Forms/ChangeLog
===================================================================
---
branches/mwf-handle-branch/Managed.Windows.Forms/Test/System.Windows.Forms/ChangeLog
2007-02-28 21:05:20 UTC (rev 73570)
+++
branches/mwf-handle-branch/Managed.Windows.Forms/Test/System.Windows.Forms/ChangeLog
2007-02-28 21:31:26 UTC (rev 73571)
@@ -1,3 +1,13 @@
+2007-02-28 Chris Toshok <[EMAIL PROTECTED]>
+
+ * ControlTest.cs: Flesh out ControlInvokeTest to make sure that
+ the Control thread dies (that Application.Run returns, basically).
+ This works in isolation, but for some reason it isn't exiting when
+ run in concert with other tests (this test is the cause of the
+ hangs running the unit tests.) Marking NotWorking for the time
+ being. This needs to be fixed before merging back to the
+ mainline, imo.
+
2007-02-12 Everaldo Canuto <[EMAIL PROTECTED]>
* LabelTest.cs: Rename PreferredSize test to PreferredWidth and
Modified:
branches/mwf-handle-branch/Managed.Windows.Forms/Test/System.Windows.Forms/ControlTest.cs
===================================================================
---
branches/mwf-handle-branch/Managed.Windows.Forms/Test/System.Windows.Forms/ControlTest.cs
2007-02-28 21:05:20 UTC (rev 73570)
+++
branches/mwf-handle-branch/Managed.Windows.Forms/Test/System.Windows.Forms/ControlTest.cs
2007-02-28 21:31:26 UTC (rev 73571)
@@ -1745,6 +1745,7 @@
}
[TestFixture]
+ [Category ("NotWorking")]
public class ControlInvokeTest {
public delegate void TestDelegate ();
@@ -1753,11 +1754,13 @@
Thread control_t;
ApplicationContext control_context;
bool delegateCalled = false;
+ bool threadDied = false;
object m;
void CreateControl ()
{
+ try {
f = new Form ();
f.ShowInTaskbar = false;
@@ -1777,11 +1780,20 @@
Console.WriteLine ("control thread running");
Application.Run (control_context);
c.Dispose ();
+ Console.WriteLine ("dying");
+ threadDied = true;
+ Monitor.Enter (m);
+ Console.WriteLine ("pulsing again");
+ Monitor.Pulse (m);
+ Monitor.Exit (m);
+ } catch (Exception e) { Console.WriteLine (e); }
}
[Test]
public void InvokeTest ()
{
+ Console.WriteLine ("hi");
+
m = new object ();
control_t = new Thread(new ThreadStart(CreateControl));
@@ -1799,14 +1811,20 @@
result = c.BeginInvoke (new TestDelegate
(delegate_call));
c.EndInvoke (result);
- Assert.AreEqual (true, delegateCalled, "Invoke1");
+ Assert.IsTrue (delegateCalled, "Invoke1");
+
+ Monitor.Wait (m);
+ Assert.IsTrue (threadDied, "Invoke2");
}
public void delegate_call () {
+ try {
/* invoked on control_context's thread */
delegateCalled = true;
f.Dispose ();
- Application.Exit ();
+ Console.WriteLine ("calling Application.Exit");
+ control_context.ExitThread ();
+ } catch (Exception e) { Console.WriteLine (e); }
}
}
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches