Selaa lähdekoodia

Fixes #1999. Prevents the mouseGrabView being executed with a null view. (#2000)

* Unit test that will fail without the fix.

* ScrollView must return true after ungrab the mouse to allow the View property run after returned.

* Fixes #1999. Prevents the mouseGrabView being executed with a null view.

* Added one more assert null check.
BDisp 2 vuotta sitten
vanhempi
commit
75c0160d96

+ 8 - 1
Terminal.Gui/Core/Application.cs

@@ -638,6 +638,11 @@ namespace Terminal.Gui {
 			}
 			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 @@ namespace Terminal.Gui {
 				// System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
 				if (mouseGrabView != null) {
 					mouseGrabView.OnMouseEvent (nme);
-					return;
+					if (mouseGrabView != null) {
+						return;
+					}
 				}
 			}
 

+ 0 - 1
Terminal.Gui/Views/ScrollView.cs

@@ -517,7 +517,6 @@ namespace Terminal.Gui {
 				horizontal.MouseEvent (me);
 			} else if (IsOverridden (me.View)) {
 				Application.UngrabMouse ();
-				return false;
 			}
 			return true;
 		}

+ 82 - 0
UnitTests/ApplicationTests.cs

@@ -1408,5 +1408,87 @@ namespace Terminal.Gui.Core {
 
 			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
+						});
+
+					Assert.Null (Application.mouseGrabView);
+
+					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 ();
+		}
 	}
 }

+ 35 - 0
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;
+	}
+}