Canvas Areas

Have I missed something?

The “portion” parameters (x,y,width,height) in invalidate and refresh do not seem to be passed through to the paint event?

Easy example: Example Projects>Graphics and Mutimedia>Animation>CanvasAreas does not work.

They work here in windows 10 using 2021r3, what os and version are you using?

This is NOT a Xojo bug, it was broken in macOS Big Sur at the OS level.

The word from Apple is that the new behavior described in my original report should be considered the correct behavior, and that -getRectsBeingDrawn:count: can no longer be relied upon. The expectation of developers who need drawing optimization that they “roll their own” system.

https://developer.apple.com/forums/thread/663256

I am MacOS and Xojo 2021 R3. I also tried Xojo 2020 R2.1 (the oldest I have) with the same result.

Thanks Sam.

Any ideas on how to “roll my own”. Setting flags etc leads to synch problems with event firing.

What I have found is that when calling invalidate( left, top, width, height, false ) the OS will only update that area to it’s buffers, so I just live without knowing what area should be painted.

However if you want to do it yourself, create a subclass, override the invalidate function (there are two AFAIK), add the rect to an array and then call super.invalidate passing in the area.

In the paint event, loop through the array (if it has values) and flush it once you’ve done your drawing.

Wow, I thought the point of using a framework like xojo was meant to insulate issues like this away from users?

Why is this not in the docs saying that this feature no longer works in Big Sur?

Why is xojo not working around this to make this “bug” transparent to its users?

If things like this aren’t addressed then xojo has a slow erosion of its feature set as well as a slow creep of features just not working as expected cross platform.

Thanks Sam.

1 Like

Probably because we didn’t know about this change.

<https://xojo.com/issue/63577>

2 Likes

I thought you and I had discussed this, but I can’t find any reference on the forum, so it musta been someone else.

The case has been reopened.

1 Like

Thanks for the example you placed in FB case 63577

T’was on back in February and I forgot that I’d logged it in Feedback.

Not defending Xojo here, but Apple also haven’t updated their documents or deprecated the function, it just doesn’t work, even though Apple’s engineers now claim that it not working is expected behavior.

Is there any chance that we can get back the feature of invalidating specific regions of a Canvas or a Window on macOS?
The real problem is that macOS instead of invalidating the rect that is given in Invalidate/Refresh always invalidates the whole Canvas/Window. This wastes a lot of resources on a large Canvas with many objects to draw.

That is probably a bug in Xojo. Xojo really caused confusion when they decided to rename the most commonly used function name “invalidate” to refresh. They’re two fundamentally different things, and should not be mixed up.
Needless to say you can bypass Xojo’s shenanigans and use a declare to tell the macOS to only update a specific rect of the canvas next time it does a view update.

// --- Objective-C
[NSView setNeedsDisplay:NSRect]

// --- Swift / App Kit
NSView.setNeedsDisplay( NSRect )

// --- SwiftUI
//     Split canvas into multiple views/layers and bind their values so
//     they update when the value changes.

You should be able to find this declare already as either part of my discontinued App Kit or most likely that plugin has it also.

2 Likes

Thanks Sam! But unfortunately this points to the core of the problem; setNeedsDisplayInRect completely ignores the passed rect and invalidates the whole view (Canvas). This could be (and is) a huge problem since Big Sur, if i remember correctly. This blog post describes it and also contains a link to discussion on Apple Developer:

My Mac is still running 14.0. I will update to 14.1.1 and check again.

Interesting. I’ve know about getRectsBeingDrawn: being broken for a while as @Greg_O_Lone and I discussed it some time ago.

In my tests (back then) with earlier versions, setNeedsDisplayInRect was continuing to clip the canvas and the performance hit of not knowing exactly which rects are dirty was minimal (in my app).

I suspect this has something do to with Apple’s progression to layers. The idea is to have multiple smaller views that are independently cached (by the macOS), instead of one single complex view where you invalidate just a rect.

Separating a complex canvas into views or layers does improve performance and making position animation silky smooth, but it can take a little while to fully get into the swing and of course it uses more memory.

I’m about to approach this topic in SwiftUI, so it’ll be interesting to see what is the recommend way with Apple’s latest and greatest.