namespace Terminal.Gui.App; public partial class ApplicationImpl { /// public event EventHandler>? ScreenChanged; private readonly object _lockScreen = new (); private Rectangle? _screen; /// public Rectangle Screen { get { lock (_lockScreen) { if (_screen == null) { _screen = Driver?.Screen ?? new (new (0, 0), new (2048, 2048)); } return _screen.Value; } } set { if (value is { } && (value.X != 0 || value.Y != 0)) { throw new NotImplementedException ("Screen locations other than 0, 0 are not yet supported"); } lock (_lockScreen) { _screen = value; } } } /// public bool ClearScreenNextIteration { get; set; } /// public bool PositionCursor () { if (Driver is null) { return false; } // Find the most focused view and position the cursor there. View? mostFocused = Navigation?.GetFocused (); // If the view is not visible or enabled, don't position the cursor if (mostFocused is null || !mostFocused.Visible || !mostFocused.Enabled) { var current = CursorVisibility.Invisible; Driver?.GetCursorVisibility (out current); if (current != CursorVisibility.Invisible) { Driver?.SetCursorVisibility (CursorVisibility.Invisible); } return false; } // If the view is not visible within it's superview, don't position the cursor Rectangle mostFocusedViewport = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = Point.Empty }); Rectangle superViewViewport = mostFocused.SuperView?.ViewportToScreen (mostFocused.SuperView.Viewport with { Location = Point.Empty }) ?? Driver.Screen; if (!superViewViewport.IntersectsWith (mostFocusedViewport)) { return false; } Point? cursor = mostFocused.PositionCursor (); Driver!.GetCursorVisibility (out CursorVisibility currentCursorVisibility); if (cursor is { }) { // Convert cursor to screen coords cursor = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = cursor.Value }).Location; // If the cursor is not in a visible location in the SuperView, hide it if (!superViewViewport.Contains (cursor.Value)) { if (currentCursorVisibility != CursorVisibility.Invisible) { Driver.SetCursorVisibility (CursorVisibility.Invisible); } return false; } // Show it if (currentCursorVisibility == CursorVisibility.Invisible) { Driver.SetCursorVisibility (mostFocused.CursorVisibility); } return true; } if (currentCursorVisibility != CursorVisibility.Invisible) { Driver.SetCursorVisibility (CursorVisibility.Invisible); } return false; } /// /// INTERNAL: Resets the Screen field to null so it will be recalculated on next access. /// private void ResetScreen () { lock (_lockScreen) { _screen = null; } } /// /// INTERNAL: Called when the application's size has changed. Sets the size of all s and fires /// the /// event. /// /// The new screen size and position. private void RaiseScreenChangedEvent (Rectangle screen) { Screen = new (Point.Empty, screen.Size); ScreenChanged?.Invoke (this, new (screen)); foreach (Toplevel t in SessionStack) { t.OnSizeChanging (new (screen.Size)); t.SetNeedsLayout (); } LayoutAndDraw (true); } private void Driver_SizeChanged (object? sender, SizeChangedEventArgs e) { RaiseScreenChangedEvent (new (new (0, 0), e.Size!.Value)); } /// public void LayoutAndDraw (bool forceRedraw = false) { List tops = [.. SessionStack]; if (Popover?.GetActivePopover () as View is { Visible: true } visiblePopover) { visiblePopover.SetNeedsDraw (); visiblePopover.SetNeedsLayout (); tops.Insert (0, visiblePopover); } bool neededLayout = View.Layout (tops.ToArray ().Reverse (), Screen.Size); if (ClearScreenNextIteration) { forceRedraw = true; ClearScreenNextIteration = false; } if (forceRedraw) { Driver?.ClearContents (); } if (Driver is { }) { Driver.Clip = new (Screen); View.Draw (tops, neededLayout || forceRedraw); Driver.Clip = new (Screen); Driver?.Refresh (); } } }