setNeedsDisplay:True not redrawing unless activated? - cocoa

I have a custom view that is a subview of the main window. I have a timer that fires a [self setNeedsDisplay:TRUE] that will update drawing on the view. But from what I can see, if I leave the application on the background and switch to another, it does not reflect the new drawing functions until I click again on the application.
What could I be missing?
Thank you,
Jose.

setNeedsDisplay will not fire if it thinks the user cant see what its drawing for obvious reason. This includes, offscreen and obscured views even when the app is running.
In an app where you might be drawing data over time you would draw all the relevant data while backgrounded out at once when the app resumes.

Related

SetNeedsDisplay on NSView triggers the redrawing of the whole views hierarchy

I'm working on an app made by a NSWindow which own a lot of custom subviews, that could be opaque or not.
Whenever I call SetNeedsDisplay: or SetNeedsDisplayInRect: on a subview, the system calls the drawRect of each single subview starting from the content view of the parent NSWindows.
How can it be avoided? How can I redraw just the dirty subview (it should be the default behaviour)? Is there something that I'm missing maybe in subclassing the NSView? Or in setting the properties or the syle of the parent NSWindow?
Thanks
The that could be opaque or not is the trouble-some bit. Any non-opaque view triggers a redraw of the entire view hierarchy, because the window must restore that views background to a pristine state. Only views set to opaque may not require anything else below them to be redrawn. They might still trigger redraws "above" though, if the opaque view itself is partially covered by other views.
Ok, I think I’ve figured it out. It seems that turning all the subviews into layer-backed views did the trick.
And this is reasonable giving the way the layers are managed by the gpu and how the layer compositing is performed.
But I still don't understand why, using the "classic" NSViews, no matter if they are opaque or not, siblings or children, overlapped or not , I cannot invalidate a single view without the system calls the re-drawing of the entire view hierarchy of the window

Detect moving the windows from one display to another

I have a window with an opengl view where content ist rendered. The problem I have in macOS is, that when I move the window from one monitor to the other, its content gets messed up. A redraw fixes the issue. Thus I need to redraw the GL Area when it gets moved from one monitor to the other. Is there any way to detect the transition of the window from one monitor to the other?
You can register for notifications that fire when the view's window changes screens: NSWindowDidChangeScreenNotification

Dynamically resizing views based based on NSOutlineView after expand/collapse animation

I'm using an NSOutlineView to display a hierarchy of tracks in a timeline, very similar to what would be seen in video editing packages. As the user expands/collapses items in the outline view, the corresponding objects in a scroll view alongside it appear and disappear.
Unfortunately, the outlineViewItemDidCollapse: and outlineViewItemDidExpand: delegate methods get called before the animation is complete, and calling frameOfCellAtColumn: on the outline view only gets the frame at that instant, while Cocoa is still animating its [dis]appearance.
As a workaround, I'm using performSelector:withObject:afterDelay: with a delay of 100ms (as is this Dynamically resize NSWindow based on NSOutlineView height person with a similar problem), but this isn't perfect (and it's smells bad). The animation isn't always finished inside 100ms, and any longer delay becomes quite noticeable.
-(void)outlineViewItemDidExpand:(NSNotification *)notification
{
// we need to delay the update to allow the outline view expand animation to
// complete. Perhaps 0.1s isn't long enough in all cases, but any longer seems
// too sluggish
[self performSelector:#selector(updateSubviewsForTimeline:) withObject:timelineView afterDelay:0.1];
}
Is there any way I can hook into the outlineViewDidExpand|Collase: methods after the animation is complete? Alternatively, can I somehow get a handle on the animation itself inside my outlineViewDidExpand|Collase: methods so I can install a callback on that?

Prevent an instance of NSView from receiving mouse events

I have an NSView in a window with core animation layer turned on.
I use this view to display images with animation from time to time. I need the entire view to be the back layer not only the images. Behind this view which I call AnimationBaseView are other views which the user interacts to.
Everything is ok except the AnimationBaseView prevents the other views from getting rightMouseDown events.
I've tried the following:
returning NO to acceptsFirstResponder to AnimationBaseView
Hiding and unhiding the AnimationBaseView as needed, but produces a nasty flicker.
Thank you for your help,
Jose.
Override - (NSView *)hitTest:(NSPoint)aPoint to return either nil or the view that should handle the mouse events

How can I trigger Core Animation on an animator proxy during a call to resizeSubviewsWithOldSize?

I have some NSViews that I'm putting in one of two layouts depending on the size of my window.
I'm adjusting the layout when the relevant superview receives the resizeSubviewsWithOldSize method.
This works, but I'd like to animate the change. So naturally I tried calling the animator proxy when I set the new frames, but the animation won't run while the user is still dragging. If I release the mouse before the animation is scheduled to be done I can see the tail end of the animation, but nothing until then. I tried making sure kCATransactionDisableActions was set to NO, but that didn't help.
Is it possible to start a new animation and actually have it run during the resize?
I don't think you can do this easily because CA's animations are run via a timer and the timer won't fire during the runloop modes that are active while the user is dragging.
If you can control the runloop as the user is dragging, play around with the runloop modes. That'll make it work. I don't think you can change it on the CA side.
This really isn't an answer, but I would advise against animating anything while dragging to resize a window. The screen is already animating (from the window moving) - further animations are likely going to be visually confusing and extraneous.
CoreAnimation effects are best used to move from one known state to another - for example, when a preference window is resizing to accompany a new pane's contents, and you know both the old and new sizes, or when you are fading an object in or out (or both). Doing animation while the window is resizing is going to be visually confusing and make it harder for the user to focus on getting the size of the window where they want it to be.

Resources