Browse Source

Brings to Mac the same bounds fix that I did to iOS, where I was queuing
the wrong chunk of data.

Starting with BigSur any screen updates will invoke the draw() method
with the whole region, regardless of how much changed.

Added a new `disableFullRedrawOnAnyChanges` property that by default
will make the Terminal avoid this new behavior. It can be controlled
by client code.

Setting this to true, will disable this OS behavior, setting it to
false, will keep the original BigSur behavior to redraw the whole
region.

For more details on this see:

https://gist.github.com/lukaskubanek/9a61ac71dc0db8bb04db2028f2635779
https://developer.apple.com/forums/thread/663256?answerId=646653022#646653022

Added an NSView.rectsBeingDrawn method to get the exposed areas - also
sort of worthless on BigSur an older if the flag is not set.

Miguel de Icaza 4 years ago
parent
commit
13d535f108

+ 12 - 3
Sources/SwiftTerm/Apple/AppleTerminalView.swift

@@ -505,7 +505,7 @@ extension TerminalView {
     {
     {
         let lineDescent = CTFontGetDescent(fontSet.normal)
         let lineDescent = CTFontGetDescent(fontSet.normal)
         let lineLeading = CTFontGetLeading(fontSet.normal)
         let lineLeading = CTFontGetLeading(fontSet.normal)
-        
+
         // draw lines
         // draw lines
         for row in terminal.buffer.yDisp..<terminal.rows + terminal.buffer.yDisp {
         for row in terminal.buffer.yDisp..<terminal.rows + terminal.buffer.yDisp {
             let lineOffset = cellDimension.height * (CGFloat(row - terminal.buffer.yDisp + 1))
             let lineOffset = cellDimension.height * (CGFloat(row - terminal.buffer.yDisp + 1))
@@ -605,8 +605,18 @@ extension TerminalView {
                 }
                 }
             }
             }
         }
         }
+
+        #if false
+        // Draws a box around the received affected area
+        NSColor.red.set ()
+        context.setLineWidth(3)
+        context.move(to: dirtyRect.origin)
+        context.addLine(to: CGPoint (x: dirtyRect.maxX, y: dirtyRect.maxY))
+        context.strokePath()
+        #endif
     }
     }
     
     
+    
     /// Update visible area
     /// Update visible area
     func updateDisplay (notifyAccessibility: Bool)
     func updateDisplay (notifyAccessibility: Bool)
     {
     {
@@ -640,7 +650,6 @@ extension TerminalView {
             let oy = region.origin.y
             let oy = region.origin.y
             region = CGRect (x: 0, y: 0, width: frame.width, height: oh + oy)
             region = CGRect (x: 0, y: 0, width: frame.width, height: oh + oy)
         }
         }
-        //print ("Region: \(region)")
         setNeedsDisplay(region)
         setNeedsDisplay(region)
         #else
         #else
         // TODO iOS: need to update the code above, but will do that when I get some real
         // TODO iOS: need to update the code above, but will do that when I get some real
@@ -670,7 +679,7 @@ extension TerminalView {
         if vy >= buffer.yDisp + buffer.rows {
         if vy >= buffer.yDisp + buffer.rows {
             caretView.removeFromSuperview()
             caretView.removeFromSuperview()
             return
             return
-        } else if terminal.cursorHidden == false {
+        } else if terminal.cursorHidden == false && caretView.superview != self {
             addSubview(caretView)
             addSubview(caretView)
         }
         }
         
         

+ 42 - 4
Sources/SwiftTerm/Mac/MacTerminalView.swift

@@ -99,7 +99,17 @@ open class TerminalView: NSView, NSTextInputClient, NSUserInterfaceValidations {
     var colors: [NSColor?] = Array(repeating: nil, count: 256)
     var colors: [NSColor?] = Array(repeating: nil, count: 256)
     var trueColors: [Attribute.Color:NSColor] = [:]
     var trueColors: [Attribute.Color:NSColor] = [:]
     var transparent = TTColor.transparent ()
     var transparent = TTColor.transparent ()
+    var isBigSur = true
     
     
+    /// This flag is automatically set to true after the initializer is called, if running on a system older than BigSur.
+    /// Starting with BigSur any screen updates will invoke the draw() method with the whole region, regardless
+    /// of how much changed.   Setting this to true, will disable this OS behavior, setting it to false, will keep
+    /// the original BigSur behavior to redraw the whole region.
+    ///
+    /// For more details on this see:
+    /// https://gist.github.com/lukaskubanek/9a61ac71dc0db8bb04db2028f2635779
+    /// https://developer.apple.com/forums/thread/663256?answerId=646653022#646653022
+    public var disableFullRedrawOnAnyChanges = false
     var fontSet: FontSet
     var fontSet: FontSet
 
 
     /// The font to use to render the terminal
     /// The font to use to render the terminal
@@ -137,6 +147,10 @@ open class TerminalView: NSView, NSTextInputClient, NSUserInterfaceValidations {
     private func setup()
     private func setup()
     {
     {
         wantsLayer = true
         wantsLayer = true
+        isBigSur = ProcessInfo.processInfo.isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 11, minorVersion: 0, patchVersion: 0))
+        if isBigSur {
+            disableFullRedrawOnAnyChanges = true
+        }
         setupScroller()
         setupScroller()
         setupOptions()
         setupOptions()
     }
     }
@@ -315,6 +329,15 @@ open class TerminalView: NSView, NSTextInputClient, NSUserInterfaceValidations {
     
     
     var userScrolling = false
     var userScrolling = false
 
 
+    override open func viewWillDraw() {
+        
+        // Starting with BigSur, it looks like even sending one pixel to be redrawn will trigger
+        // a call to draw() for the whole surface
+        if disableFullRedrawOnAnyChanges {
+            let layer = self.layer
+            layer?.contentsFormat = .RGBA8Uint
+        }
+    }
     #if false
     #if false
     override open func setNeedsDisplay(_ invalidRect: NSRect) {
     override open func setNeedsDisplay(_ invalidRect: NSRect) {
         print ("setNeeds: \(invalidRect)")
         print ("setNeeds: \(invalidRect)")
@@ -331,7 +354,6 @@ open class TerminalView: NSView, NSTextInputClient, NSUserInterfaceValidations {
         guard let currentContext = getCurrentGraphicsContext() else {
         guard let currentContext = getCurrentGraphicsContext() else {
             return
             return
         }
         }
-        
         drawTerminalContents (dirtyRect: dirtyRect, context: currentContext)
         drawTerminalContents (dirtyRect: dirtyRect, context: currentContext)
     }
     }
     
     
@@ -345,12 +367,12 @@ open class TerminalView: NSView, NSTextInputClient, NSUserInterfaceValidations {
         window?.makeFirstResponder (self)
         window?.makeFirstResponder (self)
     }
     }
 
 
-    open override var frame: NSRect {
+    open override var bounds: NSRect {
         get {
         get {
-            return super.frame
+            return super.bounds
         }
         }
         set(newValue) {
         set(newValue) {
-            super.frame = newValue
+            super.bounds = newValue
             
             
             let newRows = Int (newValue.height / cellDimension.height)
             let newRows = Int (newValue.height / cellDimension.height)
             let newCols = Int (getEffectiveWidth (rect: newValue) / cellDimension.width)
             let newCols = Int (getEffectiveWidth (rect: newValue) / cellDimension.width)
@@ -1177,6 +1199,22 @@ extension NSBezierPath {
     }
     }
 }
 }
 
 
+extension NSView {
+    func rectsBeingDrawn() -> [CGRect] {
+       var rectsPtr: UnsafePointer<CGRect>? = nil
+       var count: Int = 0
+       self.getRectsBeingDrawn(&rectsPtr, count: &count)
+
+       return Array(UnsafeBufferPointer(start: rectsPtr, count: count))
+     }
+    
+    public func pending(_ msg: String = "PENDING RECTS") {
+        print (msg)
+        for x in rectsBeingDrawn() {
+            print ("   -> \(x)")
+        }
+    }
+}
 extension NSAttributedString {
 extension NSAttributedString {
     func fuzzyHasSelectionBackground () -> Bool
     func fuzzyHasSelectionBackground () -> Bool
     {
     {

+ 2 - 0
TerminalApp/MacTerminal.xcodeproj/project.pbxproj

@@ -135,6 +135,8 @@
 				Base,
 				Base,
 			);
 			);
 			mainGroup = 49BD1A51224207B4005A2252;
 			mainGroup = 49BD1A51224207B4005A2252;
+			packageReferences = (
+			);
 			productRefGroup = 49BD1A5B224207B5005A2252 /* Products */;
 			productRefGroup = 49BD1A5B224207B5005A2252 /* Products */;
 			projectDirPath = "";
 			projectDirPath = "";
 			projectRoot = "";
 			projectRoot = "";

+ 1 - 1
TerminalApp/MacTerminal.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -2,6 +2,6 @@
 <Workspace
 <Workspace
    version = "1.0">
    version = "1.0">
    <FileRef
    <FileRef
-      location = "self:SwiftTerm.xcodeproj">
+      location = "self:">
    </FileRef>
    </FileRef>
 </Workspace>
 </Workspace>