-
-
Notifications
You must be signed in to change notification settings - Fork 647
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Animate window move/resize/swap/warp #148
Comments
I'm not particularly interested in doing this, but would not be against a PR where this is optional. |
Another animation idea: Alacritty, for example, is completely resizable. |
Any update on this? |
Just saw this on reddit, it looks so smooth |
Just to note that the mentioned |
Did anyone manage to implement it and has a compiled version of it? |
im wondering of this too |
anim.mp4I figured it is not a big problem to call |
brilliant.
brilliant. |
Did you only apply the transform in that POC, or does it also synchronise said transform with the desired window frame change? This is important because macOS itself applies transforms to windows in various contexts, and that will undo the operation. |
It is not polished at all and very hacked together, this is all I did: |
I'll probably take a shot at this for the next release, as I'm working on smoothing out the experience. I have a fairly high bar for what I consider acceptable though, so not sure if it is feasible to ship in the end. A dealbreaker for me is the ability to animate all windows that are modified in the same operation simultaneously, so that they start/end at the same time. |
Great to hear! Animating the windows in parallel would be very nice, but quite a bit of restructuring of the code base I believe. It would probably also be much better to animate from the SA directly. I only chose to not do that because then the SA would have to notify yabai when the animation is finished or unlock some kind of mutex that the SA and yabai share and that would go too far for a simple POC. This would probably also benefit greatly from your new ipc approach via shmem + mutex. When those animations are done "proper" (parallel and less flickering) it will feel very nice I am sure. What I stumbled over while implementing the POC was that once the affine transform is reset to the original transform before moving and resizing the window via AX there would sometimes be a noticeable flickering and I didn't find a way to resize the window through SLS functions, i.e. SLSSetWindowShape does not seem to be respected when set via SA. So I was stuck with the slow resize via AX. |
Pushed a proof of concept myself: https://github.com/koekeishiya/yabai/tree/animate 269d29d Remember to reinstall the scripting addition after building the above branch.
I don't think it is possible to get around this; I have attempted to do so in my version, but no guarantees that it is a universal solution. |
Resizing using the AX API is just too slow. Need to figure out some other way to resize a window.. When resizing a window using the native (mouse) handle at the edges, the operation appears to be rather snappy. I wonder if we could somehow hook into that. |
When looking at the animation happening when clicking the green fullscreen button on any windows handle I got a (janky?) idea:
I don't know if this is ok to do performance wise, but I suspect something similar is happening in the system animation to fullscreen. They additionally transition between the scaled versions of the unresized and the resized window through the animation, making it look a bit smoother. |
I had an idea that it would maybe be ok to animate the actual windows as is done, but taking a screen capture of the space at the final frame; displaying this screen capture as a topmost window and destroy it (probably some kind of blurred fade) while removing the transforms and applying the resize animation. Thanks to your comment now I recorded my screen while doing the enter/exit fullscreen application, and it actually looks like Apple themselves are doing something like this, surprisingly enough. |
I tried my idea by misusing the border to temporarily draw the capture of the window. The scripting addition is not needed for the animation at all (only for changing the opacity) and it looks very smooth. https://github.com/FelixKratz/yabai/commit/18eb2ca9d2caf1fffb8097e0378efd9826ff54c7 |
Are you able to animate the windows simultaneously using that approach though? Edit: I guess you could iterate through all windows, grab a capture of the window, and set the opacity to 0. Set the size and position using the AX API. Animate all the captures. Iterate through the list of windows, setting the opacity back to the previous value. |
In my current implementation it is single window, but if I pass a window list to the animation function (same as you have done) it will be possible to animate simultaneously. Maybe I will try to rebase to your POC and implement this method there, but I think the digest of this is that we can definitely circumvent the flickering. Maybe it would be good to use the faster SLSHW functions for window capture instead of what I am using currently. |
It works pretty well, except Edit: So the issue appears to be that the screenshot does not capture vibrancy effects among other things |
That's an awesome feature! Thanks a lot! ❤️ However, I also have problems with SIP enabled: the animations are only playing very rarely when swapping or moving windows. Only about every 7th (or even more) command triggers an animation. Not predictably though.
UPDATE |
So this is happening if you perform some action that would cancel an in-progress animation for a window and start a new animation towards a new state. If you set the animation duration to 1.0 seconds, and do What's happening is that the first swap command will trigger the start of an animation, however we need the scripting addition to hide the real window while we animate a proxy; performing a transactional switch so that it isn't actually obvious to the user that this is what's happening. Because the scripting-addition is not loaded, the swap doesn't occur, and there is no animation showing. When an animation is cancelled because a new one is started, the proxy is updated and swaps with the old proxy. This swap does not rely on the scripting addition, which is why those windows suddenly become visible. I do believe I stated that this particular config option requires SIP to be disabled. However, I agree that maybe there should be some limitation in place preventing the value to be changed from 0.0 on systems where SIP is enabled. There is no way to allow this functionality with SIP enabled, unfortunately. |
That makes sense. Think I should have read the docs first - just saw it in the changelog and jumped right into it. 😅 My bad! |
Added a guard that only allows window_animation_duration to be set if the appropriate SIP flags are disabled. |
The animation can get fairly stuttery at times. My testing shows that this is connected to disabling the update on border resize and border redraw. Even though animations use a different SLS connection, they seem to affect each other still. This patch https://github.com/FelixKratz/yabai/commit/a20e36e017e4e3257b9904625a6b0f080d9e1136 makes the animations (especially noticeable on large displays and short animation durations) dramatically smoother for my configuration. It however introduces redraw flickering since the update has not been disabled on redraw. |
Is it normal for there to be a delay before the animations play? I'm using the latest version on macOS 12.6 apple silicon. After using |
This delay is caused by actually setting the change in size/position using the accessibility API, and there is nothing that can be done to speed up that operation. The accessibility API is janky and that's really it - until Apple either improves the API/performance of it, or implements a different system for third-party software to interact with windows/applications. |
What if we let the yabai to send the window closing signal? Say implement a command like |
That would probably work, but I'd prefer something more universal. I often use Not that I am fully opposed to experimenting with something like what you mentioned. |
I have pondered a bit further with the animation system and came up with a new POC for a fade between the scaled window and the unscaled window at the end of an animation. I believe this makes animations a lot more smooth https://github.com/FelixKratz/yabai/commit/de13dbca8d62a8a453d15455c7f3adeb527a8e09: anim.mp4 |
How does that look when you hit windows that have min/max size constraints? |
A bit funny: constraint.mp4 |
@FelixKratz I'm on the latest release The text resizes after the window is set to its new location. In your video, the text resizing and window movement animation happen simultaneously. What could be the reason for this? Does your branch still have a different code? I'm using the |
This started to annoy me and I got a little bit creative, and found a way to improve the situation. |
Would love a way to just disable animations for any resize. |
|
I mean disable only for resize operations, but not for move operations. So any animations that are compromised by the stretching effect, while keeping the animations that look perfect. |
I'm not sure if that level of complexity can be handled reasonably in the animation system. I agree that the abrupt end from final animated state to displaying the actual window is not ideal. |
I think it's better, but still not something I'd leave enabled. The stretching itself is the issue. I just noticed the stretching causes window corners to deform too when their ratio changes. The only way I can think to do it, given the constraints, in an aesthetically pleasing way—and this way admittedly would take a lot more work—is to apply a strong gaussian blur to the overlay so you can't really see the window content deforming, and mask the corners so they look like standard macOS corners throughout the full animation. Screen.Recording.2024-03-03.at.00.54.53.mov |
Actually, here's another aesthetically pleasing option, this one even more complicated, but perhaps with the best possible effect:
A resize may use various combinations of the above options. After the resize, possibly alpha-fade to the window's true UI. The effect of this should be to appear as if the window doesn't relayout its UI until after the animation, but that the window frame itself still cleanly animates. |
I think that is too much work for the actual processor to do for this to feel snappy, with the way this has to work. Preparing animation state already takes between 60-130ms depending on a variety of conditions. I think we looked at how Apple performs transitions a bit further up this thread, and they fade transition between the old and new state. Admittedly their version looks better as they have access to more info than yabai does. |
FelixKratz did a more invasive alpha fade POC a couple of comments above. The window transitions approximately in the middle of the animation, so the stretch is less pronounced. Do you think such a solution would be acceptable? I guess it would be hard to tell without trying it yourself and observe the results directly. Looking at a gif is not always the same/as accurate. |
Specifically, Apple does it by performing the alpha fade during the first two thirds of the animation, with some easing function that performs most of the fade within the first few frames. As you noted, this has the effect that by the time the resize animation is slowing down towards the end, the window has already faded to the new state, and so the warping is much less noticeable. They don't even do any corner masking. I think using the same timings as Apple is as good as anyone can ask for 😄 |
Discussion / Feature request
This is a long shot, and probably far off in the future. This has been previously discussed in https://github.com/koekeishiya/chunkwm/issues/144.
I've dug up some stuff regarding this.
CGS*
functions https://github.com/ChromiumWebApps/chromium/blob/c7361d39be8abd1574e6ce8957c8dbddd4c6ccf7/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.mmCGSSetWindowWarp
works http://kevin.sb.org/2006/07/23/cgssetwindowwarp-explained/CGSSetWindowWarp
andCGSSetWindowTranslation
for custom animations https://github.com/sailesha/CGSSetWindowWarp-Sample/blob/master/windowAnimation.mmObviously all the above examples require access to the NSWindow instance for async animations, which is inaccessible from the Dock process—which is the only process yabai injects code into.
Simply calling
SLSSetWindowTransformation
with aCGAffineTransform
(e..gCGAffineTransformMakeTranslation(100, 100)
to move a window 100 right and 100 down) will move the window, but this is not animated. Calling this repeatedly will likely cause lag.And now here's the long shot that I'd love to see investigated in the future: There are additional functions called
SLSTransactionCreate
andSLSTransactionCommit
, with variants of the transform and warp functions namedSLSTransactionWindowTransform
and so on. Assuming this works similar toCATransaction
on iOS, this could then be used to animate multiple windows with a duration and at the same time.These
SLSTransaction*
functions are available (on 10.15 dev beta 4 currently):nm /System/Library/PrivateFrameworks/SkyLight.framework/SkyLight | grep SLSTransaction
Why? Look at this example from i3. Looks nice, doesn't it?
The text was updated successfully, but these errors were encountered: