Is [NSWindow setFrame:display:] API asynchronous? - cocoa

I have a strange UI behavior which made me think that this API might be asynchronous. Assuming it is (async), I've made some changes and now the UI works as expected. I didn't find the answer in Apple's documentation.
Is anyone familiar or had some experience with this? Is it really async? Thanks!
EDIT: All UI changes are being made from the main thread.

setFrame:display: updates the frame and tells the system to redraw the window (and possibly the subviews) during its next drawing cycle. Cocoa drawing is always done during its drawing cycle, not at the moment you call a drawing method. See What is the most robust way to force a UIView to redraw? for some more discussion on that.
This is better thought of as drawing being "consolidated" rather than "asynchronous." Unless there are animations, all drawing should generally be complete before the next event loop. It's possible that a view will somehow delay its drawing to a later event loop, but rare. Layer-backed views in 10.8+ can support actual async drawing, but this is not the default.
From you description, it's possible you're calling setFrame:display: from a thread other than the main thread. AppKit drawing is not thread safe. You cannot call drawing methods from anywhere but the main thread, or you'll get "strange UI behavior." (This isn't completely true. On OS X, you can use lockFocus to draw from other threads, but they still won't actually be applied until the next drawing cycle after you unlock focus. But normally it's best just to draw from the main thread in modern OS X since GCD makes this simple.)

Related

Updating an NSView with processing in a separate thread

Suppose you have a scrollable NSView. When you scroll it, the part coming into the clipping rectangle will need to be refreshed, and the view's drawRect (Swift draw) method will be called for a rectangle containing that new part. Suppose now that before that part can be drawn, some time-consuming processing will need to be done. Since you don't want to burden the main thread (from which drawRect is called) with that processing, you might want to unload it on a secondary thread. Now my question is, what's a good way to do this? For example, you can:
Initiate asynchronous processing from drawRect, exit it without drawing, and have the secondary thread, when it's finished, store the data somewhere and call setNeedsDisplay and thus have drawRect get called again.
As above, but when the processing is finished, draw into the view directly (in the main thread), without going through drawRect.
Set canDrawConcurrently for the view beforehand; but that, as far as I can tell, will not necessarily force drawRect into a secondary thread, unless the system decides to do so.
Or, maybe some other way? This seems like a common enough situation, but I can't find any tips on how to do this in a clean way.

drawRect suddenly stops being called

Using XCode 5.1 with custom OpenGL view.
I have a separate thread that processes data and calls setNeedsDisplay to refresh the display.
This is working well, but sometimes after running for a while and using other apps, when I return to my app, drawRect of the OpenGL view is stopped being called.
I see that setNeedsDisplay is being called and, drawRect is called whenever I resize the window.
Can anyone suggest a solution or at least a way to track down the reason for the sudden change in this behavior?
To whoever might be interested:
Seems like calling setNeedsDisplay from another thread might cause problems, together with a high frequency of these calls.
I've significantly lowered the amount of calls to setNeedsDisplay and changed the calls to performSelectorOnMainThread and it seems to solve the probem.

Properly push NSViews

I had a great system (It worked but was probably not the correct way to accomplish the task) going to animating one NSView over another. The user clicked a button and an NSView flew in over the other "replacing" it. The problem came in with window resizing. Due to the way I set it up, one view was sitting in a non-visible location and animating in with animator, resizing was nearly impossible. I also tried this which seemed promising but failed to deliver a method (and I couldn't come up with one) for handeling window resizes. So how can one accomplish the seemingly simple task of swapping views with a nice transition? Sorry for the long winded question and hopefully I explained the system I had clearly enough.
Thanks for any help/advice
Just add your controller as the window's delegate and implement the windowWillResize:toSize: delegate method.
In your implementation of the method you should set the size of your off-screen view appropriately.

Layer backed NSOpenGLView + animation timer = strange drawing behavior?

I am creating an application which subclasses NSOpenGLView to do some OpenGL drawings. Now i wanted to add an overlay control, similar to QuickTime X. First thing i tried was setting NSOpenGLCPSurfaceOrder to -1 and making my window none-opaque. It did work, but i lost the windows shadow, so not a viable solution.
I then made my NSOpenGLView subclass layer-backed by calling [setWantsLayer:YES] and adding my control box as a subview. It worked, but i noticed a big drop in performance. I did some research and found this:
I am using an NSTimer object to call a method [timerFired:] 60 times per second. Works perfectly. The only thing i do within this method is calling [self setNeedsDisplay:YES], because when using a layer-backed OpenGLView one needs to overload the [drawRect:rect] method and do all the OpenGL drawing there. The problem: [drawRect:rect] often gets called although the timer didn't fire.
At first i thought "of course it does, it draws the NSOpenGLView, so it might be called by the window manager or something". So deleted my timer object to determine how it was called between [timerFired:] calls. The result: It wasn't called at all, at least not when not resizing or dragging the window.
So next i experimented with my timers time interval. Turns out, up until 55 times per second the [drawRect:rect] is called between 60 and 70 times per second, and from a timer interval of 59 times a second onward the [drawRect:rect] is called between 100 and 120 times a second.
I suspect that this highly unpredictable manner in which my drawing is called leads to the performance loss, either by being uneven or by clogging the thread with a lot of OpenGL drawings and not enough time to be executed or something. I also read that layer-backed OpenGLViews don't work with vsync, although i can't confirm this.
Does anyone have an explanation? Does anyone have an idea on how to only draw my OpenGL on timer fires?
I already tried the naive approach and added a boolean variable, set it true in my [timerFired:] and made my [drawRect:rect] only calling the OpenGL drawing method if the variable is true. The result was an extremely flickery and stuttery animation, so no luck.
What about using an CAOpenGLLayer with asynchronous animation oder CVDisplayLink? Would either help?
edit another thing which might be helpful information: I already used [setNeedsDisplay:YES] without my view being layer-backed, so i could easily switch between layer-backed and not-layer-backed, and i didn't have any of the problems described above, so it definitely has to do with my view being layer-backed. Everything gets a mess by just calling [setWantsLayer:YES].
So i replaced my NSTimer object with a CVDisplayLink and everything is smooth again. Although i don't actually understand why. It seems like requesting a backing layer broke the vertical sync, but it does not explain the random calls to drawRect that appeared out of nowhere.
Also i would really like to if vsync works with a layer backed NSOpenGLView and / or with a CAOpenGLLayer. I can't find any official information.

SFML window resizing events blocking the main thread

I just started using the SFML library and its fantastic. However when resizing a window by dragging the corner with my mouse i don't get the resize events until i release the mouse. This means i can't update my graphics until the mouse is released (game loop is on the gui thread) and is also causing a massive flood of events to come through of all the resize positions.
How can i make it so resizing doesn't block the thread?
Windows causes this. GetEvent() becomes blocking if you move or resize the window.
(Another funny little reason to hate this OS...)
I have solved this with a separate event-polling thread. Take a look at this:
(The interesting part for you is entirely in main.cpp.)
https://bitbucket.org/torokati44/netframework/src/93bdf20d0f65/main.cpp

Resources