From 8f1091272f8b72332e6082999601637710024df1 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 8 Sep 2022 21:17:30 +0100 Subject: [PATCH 1/4] Unit test that will fail without the fix. --- UnitTests/ApplicationTests.cs | 80 +++++++++++++++++++++++++++++++++++ UnitTests/ReflectionTools.cs | 35 +++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 UnitTests/ReflectionTools.cs diff --git a/UnitTests/ApplicationTests.cs b/UnitTests/ApplicationTests.cs index 5f582535ee..2d2db5bd73 100644 --- a/UnitTests/ApplicationTests.cs +++ b/UnitTests/ApplicationTests.cs @@ -1408,5 +1408,85 @@ public void SynchronizationContext_CreateCopy () Application.Shutdown (); } + + [Fact, AutoInitShutdown] + public void MouseGrabView_WithNullMouseEventView () + { + var tf = new TextField () { Width = 10 }; + var sv = new ScrollView () { + Width = Dim.Fill (), + Height = Dim.Fill (), + ContentSize = new Size (100, 100) + }; + + sv.Add (tf); + Application.Top.Add (sv); + + var iterations = -1; + + Application.Iteration = () => { + iterations++; + if (iterations == 0) { + Assert.True (tf.HasFocus); + Assert.Null (Application.mouseGrabView); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 5, + Y = 5, + Flags = MouseFlags.ReportMousePosition + }); + + Assert.Equal (sv, Application.mouseGrabView); + + MessageBox.Query ("Title", "Test", "Ok"); + + Assert.Null (Application.mouseGrabView); + } else if (iterations == 1) { + Assert.Equal (sv, Application.mouseGrabView); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 5, + Y = 5, + Flags = MouseFlags.ReportMousePosition + }); + + Assert.Null (Application.mouseGrabView); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 40, + Y = 12, + Flags = MouseFlags.ReportMousePosition + }); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 0, + Y = 0, + Flags = MouseFlags.Button1Pressed + }); + + Assert.Null (Application.mouseGrabView); + + Application.RequestStop (); + } else if (iterations == 2) { + Assert.Null (Application.mouseGrabView); + + Application.RequestStop (); + } + }; + + Application.Run (); + } } } diff --git a/UnitTests/ReflectionTools.cs b/UnitTests/ReflectionTools.cs new file mode 100644 index 0000000000..3f661bc5f2 --- /dev/null +++ b/UnitTests/ReflectionTools.cs @@ -0,0 +1,35 @@ +using System; +using System.Reflection; + +public static class ReflectionTools { + // If the class is non-static + public static Object InvokePrivate (Object objectUnderTest, string method, params object [] args) + { + Type t = objectUnderTest.GetType (); + return t.InvokeMember (method, + BindingFlags.InvokeMethod | + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.Static, + null, + objectUnderTest, + args); + } + // if the class is static + public static Object InvokePrivate (Type typeOfObjectUnderTest, string method, params object [] args) + { + MemberInfo [] members = typeOfObjectUnderTest.GetMembers (BindingFlags.NonPublic | BindingFlags.Static); + foreach (var member in members) { + if (member.Name == method) { + return typeOfObjectUnderTest.InvokeMember (method, + BindingFlags.NonPublic | + BindingFlags.Static | + BindingFlags.InvokeMethod, + null, + typeOfObjectUnderTest, + args); + } + } + return null; + } +} From 43efcb6d626b389821538aaeb796482f5c9181d5 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 8 Sep 2022 21:28:06 +0100 Subject: [PATCH 2/4] ScrollView must return true after ungrab the mouse to allow the View property run after returned. --- Terminal.Gui/Views/ScrollView.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Terminal.Gui/Views/ScrollView.cs b/Terminal.Gui/Views/ScrollView.cs index a77a8f2aa2..306261dae3 100644 --- a/Terminal.Gui/Views/ScrollView.cs +++ b/Terminal.Gui/Views/ScrollView.cs @@ -517,7 +517,6 @@ public override bool MouseEvent (MouseEvent me) horizontal.MouseEvent (me); } else if (IsOverridden (me.View)) { Application.UngrabMouse (); - return false; } return true; } From 5703fc38c7403f3530cf48f35e20b3b179cd64c8 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 8 Sep 2022 21:30:59 +0100 Subject: [PATCH 3/4] Fixes #1999. Prevents the mouseGrabView being executed with a null view. --- Terminal.Gui/Core/Application.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index 81f28ee330..2632c69bef 100644 --- a/Terminal.Gui/Core/Application.cs +++ b/Terminal.Gui/Core/Application.cs @@ -638,6 +638,11 @@ static void ProcessMouseEvent (MouseEvent me) } RootMouseEvent?.Invoke (me); if (mouseGrabView != null) { + if (view == null) { + UngrabMouse (); + return; + } + var newxy = mouseGrabView.ScreenToView (me.X, me.Y); var nme = new MouseEvent () { X = newxy.X, @@ -653,7 +658,9 @@ static void ProcessMouseEvent (MouseEvent me) // System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}"); if (mouseGrabView != null) { mouseGrabView.OnMouseEvent (nme); - return; + if (mouseGrabView != null) { + return; + } } } From f6397abc13b40bcfa7b7de924d95c019f05ae587 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 8 Sep 2022 22:00:52 +0100 Subject: [PATCH 4/4] Added one more assert null check. --- UnitTests/ApplicationTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UnitTests/ApplicationTests.cs b/UnitTests/ApplicationTests.cs index 2d2db5bd73..1122bce239 100644 --- a/UnitTests/ApplicationTests.cs +++ b/UnitTests/ApplicationTests.cs @@ -1467,6 +1467,8 @@ public void MouseGrabView_WithNullMouseEventView () Flags = MouseFlags.ReportMousePosition }); + Assert.Null (Application.mouseGrabView); + ReflectionTools.InvokePrivate ( typeof (Application), "ProcessMouseEvent",