diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs
index eb1200999f..f0764905c4 100644
--- a/Terminal.Gui/Core/Application.cs
+++ b/Terminal.Gui/Core/Application.cs
@@ -581,7 +581,22 @@ static View FindTopFromView (View view)
return top;
}
- internal static View mouseGrabView;
+ static View mouseGrabView;
+
+ ///
+ /// The view that grabbed the mouse, to where will be routed all the mouse events.
+ ///
+ public static View MouseGrabView => mouseGrabView;
+
+ ///
+ /// Event to be invoked when a view grab the mouse.
+ ///
+ public static event Action GrabbedMouse;
+
+ ///
+ /// Event to be invoked when a view ungrab the mouse.
+ ///
+ public static event Action UnGrabbedMouse;
///
/// Grabs the mouse, forcing all mouse events to be routed to the specified view until UngrabMouse is called.
@@ -592,6 +607,7 @@ public static void GrabMouse (View view)
{
if (view == null)
return;
+ OnGrabbedMouse (view);
mouseGrabView = view;
Driver.UncookMouse ();
}
@@ -601,10 +617,27 @@ public static void GrabMouse (View view)
///
public static void UngrabMouse ()
{
+ if (mouseGrabView == null)
+ return;
+ OnUnGrabbedMouse (mouseGrabView);
mouseGrabView = null;
Driver.CookMouse ();
}
+ static void OnGrabbedMouse (View view)
+ {
+ if (view == null)
+ return;
+ GrabbedMouse?.Invoke (view);
+ }
+
+ static void OnUnGrabbedMouse (View view)
+ {
+ if (view == null)
+ return;
+ UnGrabbedMouse?.Invoke (view);
+ }
+
///
/// Merely a debugging aid to see the raw mouse events
///
@@ -656,7 +689,7 @@ static void ProcessMouseEvent (MouseEvent me)
lastMouseOwnerView?.OnMouseLeave (me);
}
// System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
- if (mouseGrabView != null && mouseGrabView.OnMouseEvent (nme)) {
+ if (mouseGrabView?.OnMouseEvent (nme) == true) {
return;
}
}
diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs
index e40d852b5b..804ddb5ed3 100644
--- a/Terminal.Gui/Views/Menu.cs
+++ b/Terminal.Gui/Views/Menu.cs
@@ -1816,7 +1816,7 @@ public override bool MouseEvent (MouseEvent me)
internal bool HandleGrabView (MouseEvent me, View current)
{
- if (Application.mouseGrabView != null) {
+ if (Application.MouseGrabView != null) {
if (me.View is MenuBar || me.View is Menu) {
var mbar = GetMouseGrabViewInstance (me.View);
if (mbar != null) {
@@ -1890,7 +1890,7 @@ internal bool HandleGrabView (MouseEvent me, View current)
//if (!(me.View is MenuBar) && !(me.View is Menu) && me.Flags != MouseFlags.Button1Pressed))
// return false;
- //if (Application.mouseGrabView != null) {
+ //if (Application.MouseGrabView != null) {
// if (me.View is MenuBar || me.View is Menu) {
// me.X -= me.OfX;
// me.Y -= me.OfY;
@@ -1905,8 +1905,8 @@ internal bool HandleGrabView (MouseEvent me, View current)
// return true;
//}
- //if (Application.mouseGrabView != null) {
- // if (Application.mouseGrabView == me.View && me.View == current) {
+ //if (Application.MouseGrabView != null) {
+ // if (Application.MouseGrabView == me.View && me.View == current) {
// me.X -= me.OfX;
// me.Y -= me.OfY;
// } else if (me.View != current && me.View is MenuBar && me.View is Menu) {
@@ -1927,7 +1927,7 @@ internal bool HandleGrabView (MouseEvent me, View current)
MenuBar GetMouseGrabViewInstance (View view)
{
- if (view == null || Application.mouseGrabView == null) {
+ if (view == null || Application.MouseGrabView == null) {
return null;
}
@@ -1938,7 +1938,7 @@ MenuBar GetMouseGrabViewInstance (View view)
hostView = ((Menu)view).host;
}
- var grabView = Application.mouseGrabView;
+ var grabView = Application.MouseGrabView;
MenuBar hostGrabView = null;
if (grabView is MenuBar) {
hostGrabView = (MenuBar)grabView;
diff --git a/Terminal.Gui/Views/ScrollBarView.cs b/Terminal.Gui/Views/ScrollBarView.cs
index f584a2ec7d..80c5b6ee37 100644
--- a/Terminal.Gui/Views/ScrollBarView.cs
+++ b/Terminal.Gui/Views/ScrollBarView.cs
@@ -357,7 +357,7 @@ void ShowHideScrollBars (bool redraw = true)
} else if (otherScrollBarView != null && otherScrollBarView.contentBottomRightCorner != null) {
otherScrollBarView.contentBottomRightCorner.Visible = false;
}
- if (Application.mouseGrabView != null && Application.mouseGrabView == this) {
+ if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
Application.UngrabMouse ();
}
} else if (contentBottomRightCorner != null) {
@@ -638,9 +638,9 @@ public override bool MouseEvent (MouseEvent me)
var pos = Position;
if (me.Flags != MouseFlags.Button1Released
- && (Application.mouseGrabView == null || Application.mouseGrabView != this)) {
+ && (Application.MouseGrabView == null || Application.MouseGrabView != this)) {
Application.GrabMouse (this);
- } else if (me.Flags == MouseFlags.Button1Released && Application.mouseGrabView != null && Application.mouseGrabView == this) {
+ } else if (me.Flags == MouseFlags.Button1Released && Application.MouseGrabView != null && Application.MouseGrabView == this) {
lastLocation = -1;
Application.UngrabMouse ();
return true;
diff --git a/Terminal.Gui/Views/ScrollView.cs b/Terminal.Gui/Views/ScrollView.cs
index 306261dae3..8202751786 100644
--- a/Terminal.Gui/Views/ScrollView.cs
+++ b/Terminal.Gui/Views/ScrollView.cs
@@ -227,7 +227,7 @@ public override void Add (View view)
void View_MouseLeave (MouseEventArgs e)
{
- if (Application.mouseGrabView != null && Application.mouseGrabView != vertical && Application.mouseGrabView != horizontal) {
+ if (Application.MouseGrabView != null && Application.MouseGrabView != vertical && Application.MouseGrabView != horizontal) {
Application.UngrabMouse ();
}
}
diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs
index 3f9ae85f01..5852c7051b 100644
--- a/Terminal.Gui/Views/TextField.cs
+++ b/Terminal.Gui/Views/TextField.cs
@@ -249,9 +249,9 @@ void TextField_Initialized (object sender, EventArgs e)
///
public override bool OnLeave (View view)
{
- if (Application.mouseGrabView != null && Application.mouseGrabView == this)
+ if (Application.MouseGrabView != null && Application.MouseGrabView == this)
Application.UngrabMouse ();
- //if (SelectedLength != 0 && !(Application.mouseGrabView is MenuBar))
+ //if (SelectedLength != 0 && !(Application.MouseGrabView is MenuBar))
// ClearAllSelection ();
return base.OnLeave (view);
@@ -1049,7 +1049,7 @@ public override bool MouseEvent (MouseEvent ev)
int x = PositionCursor (ev);
isButtonReleased = false;
PrepareSelection (x);
- if (Application.mouseGrabView == null) {
+ if (Application.MouseGrabView == null) {
Application.GrabMouse (this);
}
} else if (ev.Flags == MouseFlags.Button1Released) {
diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs
index f671a5264f..edbdb8bd3f 100644
--- a/Terminal.Gui/Views/TextView.cs
+++ b/Terminal.Gui/Views/TextView.cs
@@ -4328,7 +4328,7 @@ public override bool MouseEvent (MouseEvent ev)
}
lastWasKill = false;
columnTrack = currentColumn;
- if (Application.mouseGrabView == null) {
+ if (Application.MouseGrabView == null) {
Application.GrabMouse (this);
}
} else if (ev.Flags.HasFlag (MouseFlags.Button1Released)) {
@@ -4407,7 +4407,7 @@ void ProcessMouseClick (MouseEvent ev, out List line)
///
public override bool OnLeave (View view)
{
- if (Application.mouseGrabView != null && Application.mouseGrabView == this) {
+ if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
Application.UngrabMouse ();
}
diff --git a/UnitTests/ApplicationTests.cs b/UnitTests/ApplicationTests.cs
index 56fdb9223f..e0f331e747 100644
--- a/UnitTests/ApplicationTests.cs
+++ b/UnitTests/ApplicationTests.cs
@@ -1144,7 +1144,7 @@ public void Internal_Tests ()
Assert.NotNull (Application.Top);
var rs = Application.Begin (Application.Top);
Assert.Equal (Application.Top, rs.Toplevel);
- Assert.Null (Application.mouseGrabView);
+ Assert.Null (Application.MouseGrabView);
Assert.Null (Application.WantContinuousButtonPressedView);
Assert.False (Application.DebugDrawBounds);
Assert.False (Application.ShowChild (Application.Top));
@@ -1428,7 +1428,7 @@ public void MouseGrabView_WithNullMouseEventView ()
iterations++;
if (iterations == 0) {
Assert.True (tf.HasFocus);
- Assert.Null (Application.mouseGrabView);
+ Assert.Null (Application.MouseGrabView);
ReflectionTools.InvokePrivate (
typeof (Application),
@@ -1439,13 +1439,13 @@ public void MouseGrabView_WithNullMouseEventView ()
Flags = MouseFlags.ReportMousePosition
});
- Assert.Equal (sv, Application.mouseGrabView);
+ Assert.Equal (sv, Application.MouseGrabView);
MessageBox.Query ("Title", "Test", "Ok");
- Assert.Null (Application.mouseGrabView);
+ Assert.Null (Application.MouseGrabView);
} else if (iterations == 1) {
- Assert.Equal (sv, Application.mouseGrabView);
+ Assert.Equal (sv, Application.MouseGrabView);
ReflectionTools.InvokePrivate (
typeof (Application),
@@ -1456,7 +1456,7 @@ public void MouseGrabView_WithNullMouseEventView ()
Flags = MouseFlags.ReportMousePosition
});
- Assert.Null (Application.mouseGrabView);
+ Assert.Null (Application.MouseGrabView);
ReflectionTools.InvokePrivate (
typeof (Application),
@@ -1467,7 +1467,7 @@ public void MouseGrabView_WithNullMouseEventView ()
Flags = MouseFlags.ReportMousePosition
});
- Assert.Null (Application.mouseGrabView);
+ Assert.Null (Application.MouseGrabView);
ReflectionTools.InvokePrivate (
typeof (Application),
@@ -1478,11 +1478,11 @@ public void MouseGrabView_WithNullMouseEventView ()
Flags = MouseFlags.Button1Pressed
});
- Assert.Null (Application.mouseGrabView);
+ Assert.Null (Application.MouseGrabView);
Application.RequestStop ();
} else if (iterations == 2) {
- Assert.Null (Application.mouseGrabView);
+ Assert.Null (Application.MouseGrabView);
Application.RequestStop ();
}
@@ -1490,5 +1490,68 @@ public void MouseGrabView_WithNullMouseEventView ()
Application.Run ();
}
+
+ [Fact, AutoInitShutdown]
+ public void MouseGrabView_GrabbedMouse_UnGrabbedMouse ()
+ {
+ View grabView = null;
+ var count = 0;
+
+ var view1 = new View ();
+ var view2 = new View ();
+
+ Application.GrabbedMouse += Application_GrabbedMouse;
+ Application.UnGrabbedMouse += Application_UnGrabbedMouse;
+
+ Application.GrabMouse (view1);
+ Assert.Equal (0, count);
+ Assert.Equal (grabView, view1);
+ Assert.Equal (view1, Application.MouseGrabView);
+
+ Application.UngrabMouse ();
+ Assert.Equal (1, count);
+ Assert.Equal (grabView, view1);
+ Assert.Null (Application.MouseGrabView);
+
+ Application.GrabbedMouse += Application_GrabbedMouse;
+ Application.UnGrabbedMouse += Application_UnGrabbedMouse;
+
+ Application.GrabMouse (view2);
+ Assert.Equal (1, count);
+ Assert.Equal (grabView, view2);
+ Assert.Equal (view2, Application.MouseGrabView);
+
+ Application.UngrabMouse ();
+ Assert.Equal (2, count);
+ Assert.Equal (grabView, view2);
+ Assert.Null (Application.MouseGrabView);
+
+ void Application_GrabbedMouse (View obj)
+ {
+ if (count == 0) {
+ Assert.Equal (view1, obj);
+ grabView = view1;
+ } else {
+ Assert.Equal (view2, obj);
+ grabView = view2;
+ }
+
+ Application.GrabbedMouse -= Application_GrabbedMouse;
+ }
+
+ void Application_UnGrabbedMouse (View obj)
+ {
+ if (count == 0) {
+ Assert.Equal (view1, obj);
+ Assert.Equal (grabView, obj);
+ } else {
+ Assert.Equal (view2, obj);
+ Assert.Equal (grabView, obj);
+ }
+ count++;
+
+ Application.UnGrabbedMouse -= Application_UnGrabbedMouse;
+ }
+ }
}
}
diff --git a/UnitTests/ContextMenuTests.cs b/UnitTests/ContextMenuTests.cs
index 5df3b07ce2..a0c88168ae 100644
--- a/UnitTests/ContextMenuTests.cs
+++ b/UnitTests/ContextMenuTests.cs
@@ -519,38 +519,38 @@ public void ContextMenu_Is_Closed_If_Another_MenuBar_Is_Open_Or_Vice_Versa ()
Application.Top.Add (menu);
- Assert.Null (Application.mouseGrabView);
+ Assert.Null (Application.MouseGrabView);
cm.Show ();
Assert.True (ContextMenu.IsShow);
- Assert.Equal (cm.MenuBar, Application.mouseGrabView);
+ Assert.Equal (cm.MenuBar, Application.MouseGrabView);
Assert.False (menu.IsMenuOpen);
Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ())));
Assert.False (ContextMenu.IsShow);
- Assert.Equal (menu, Application.mouseGrabView);
+ Assert.Equal (menu, Application.MouseGrabView);
Assert.True (menu.IsMenuOpen);
cm.Show ();
Assert.True (ContextMenu.IsShow);
- Assert.Equal (cm.MenuBar, Application.mouseGrabView);
+ Assert.Equal (cm.MenuBar, Application.MouseGrabView);
Assert.False (menu.IsMenuOpen);
Assert.False (menu.OnKeyDown (new KeyEvent (Key.Null, new KeyModifiers () { Alt = true })));
Assert.True (menu.OnKeyUp (new KeyEvent (Key.Null, new KeyModifiers () { Alt = true })));
Assert.False (ContextMenu.IsShow);
- Assert.Equal (menu, Application.mouseGrabView);
+ Assert.Equal (menu, Application.MouseGrabView);
Assert.True (menu.IsMenuOpen);
cm.Show ();
Assert.True (ContextMenu.IsShow);
- Assert.Equal (cm.MenuBar, Application.mouseGrabView);
+ Assert.Equal (cm.MenuBar, Application.MouseGrabView);
Assert.False (menu.IsMenuOpen);
Assert.False (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.ReportMousePosition, View = menu }));
Assert.True (ContextMenu.IsShow);
- Assert.Equal (cm.MenuBar, Application.mouseGrabView);
+ Assert.Equal (cm.MenuBar, Application.MouseGrabView);
Assert.False (menu.IsMenuOpen);
Assert.True (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.Button1Clicked, View = menu }));
Assert.False (ContextMenu.IsShow);
- Assert.Equal (menu, Application.mouseGrabView);
+ Assert.Equal (menu, Application.MouseGrabView);
Assert.True (menu.IsMenuOpen);
}
diff --git a/UnitTests/ScrollBarViewTests.cs b/UnitTests/ScrollBarViewTests.cs
index 12215d1540..0248674bf8 100644
--- a/UnitTests/ScrollBarViewTests.cs
+++ b/UnitTests/ScrollBarViewTests.cs
@@ -947,7 +947,7 @@ This is a test
Flags = MouseFlags.Button1Clicked
});
- Assert.Null (Application.mouseGrabView);
+ Assert.Null (Application.MouseGrabView);
Assert.True (clicked);
clicked = false;
@@ -974,7 +974,7 @@ This is a test
Flags = MouseFlags.Button1Clicked
});
- Assert.Null (Application.mouseGrabView);
+ Assert.Null (Application.MouseGrabView);
Assert.True (clicked);
Assert.Equal (5, sbv.Size);
Assert.False (sbv.ShowScrollIndicator);