Cursor Rectangle Limit in Catalina

I have an app that breaks under Catalina. I need a large number of cursor rectangles but in Catalina on adding the 251st cursor rectangle it throws the exception:


assertion failure: "_needsGeometryInWindowDidChangeNotificationCount < (1 << 8) - 1" -> 0


Is there any simple work around for this? It would be a lot simpler if one could define a Cursor Region rather than a cursor rectangle.

Replies

Most likely they use an UInt8 to store the count. So there is nothing to do against it.


Could you show how you create the cursor rectangles ? (To see if you could create in different classes ? (that's just a very open question).


Could you explain as well why you need so many ? May be you could find a different design.

I have an openGL view displaying a scene. There are 33 triangular regions which the user can interact with. I divide these regions into small cursor rectangles so when the user moves the mouse over an active region the curser changes from the arrow to the open hand cursor.


I can fix the thing by commenting out one line of code but then I lose the user feedback.

In a somehow similar situation (2 triangles in a rect), I handled it with the following design:


- subclass NSView (in your case for the triangle), may be with property to define its orientation


@IBDesignable class SplitSquareView: NSView {
   
    @IBInspectable var orientationNOSE : Bool = true    // set on init() or in IB
   
     enum subPart : Int {
        case all = 0 
        case top
        case bottom
    }


- define the drawRect to draw it

- override the mouse events, as

override func mouseMoved(with theEvent: NSEvent) { }

- set the cursor there from a preset of cursor shapes.


Here an example to illustrate:


    override func mouseMoved(with theEvent: NSEvent) {
    
        let point = convert(theEvent.locationInWindow, from: nil)
        var s: CGFloat
        if orientationNOSE {  {     // NorthWet to SouthEast separation
            s = point.x + point.y
            if s < self.frame.size.width {
                drawPart = .bottom
                triangleSOCursor!.set() // SW pointing triangle cursor
            } else {
                drawPart = .top
                triangleNECursor!.set()  // NE pointing triangle cursor
            }
        } else {            // SouthWest to NorthEast separation
            s = point.y - point.x
            if s < 0 {
                drawPart = .bottom
                triangleSECursor!.set() // SE pointing triangle cursor
            } else {
                drawPart = .top
                triangleNOCursor!.set()  // NW pointing triangle cursor
            }
        }
    
        setNeedsDisplay(self.bounds)
    }



Did the same for


override func mouseEntered(with theEvent: NSEvent) { }


override func mouseExited(with theEvent: NSEvent) { }


override func mouseDown(with theEvent: NSEvent) {


    override func cursorUpdate(with event: NSEvent) {
        let point = convert(event.locationInWindow, from: nil)

        var s: CGFloat
        if orientationNOSE { 
            let s = point.x + point.y
            if s < self.frame.size.width {
                triangleSOCursor!.set()
            } else {
                triangleNECursor!.set()
            }
        } else {            // SONE
            s = point.y - point.x
            if s < 0 {
                triangleSECursor!.set() 
            } else {
                triangleNOCursor!.set()  
            }
        }
    }



Doing so, you should not reach the limit of 255.


Tell me if that makes sense for you.

Yes, to get it to work as it stands now I'm going to have reduce the number of rectangles. I may be able to merge some of them into larger rectangles. I'll have to dig into the code.


The thing is the geometry of the hit triangles is not well defined. The original geometry has been rotated around and projected onto the display in OpenGL. Many are not visible and have been culled. In the present code I determine where they are by reading pixles out of the frame buffer.

Many are not visible and have been culled. In the present code I determine where they are by reading pixles out of the frame buffer.


Wooh !


Not sure relying on the bit map is a very robust solution. You should find a way to access the objects themselves.

No, it's what you have to do in OpenGl. The problem is determining what object in a 3D rendered scene is under the mouse. This is "picking" or "hit testing". I use the standard tecnique of rendering the scene off screen giving each object one is interested in a unique "color". One then reads the pixels under the mouse to determine which if any of the objects is hit.


Looking at my code, what I have done is divide the view into a 100x100 grid of rectangles. I then scan through and any rectangle inside a hit triangle gets added to my array of cursor rectangles. I now am working on scanning through this list and merging adjacent rectangles. I should be able to significantly reduce the number of cursor rectangles required. The thing is I shouldn't have to do this. Power to the developer. If I want to have three or four hundred cursor rectangles the API shouldn't prevent me.