-
-
Notifications
You must be signed in to change notification settings - Fork 697
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
WIP: atomically apply window state changes #2911
Conversation
`Core.masked` is a context manager that lets us apply a series of changes to windows under a set of temporary conditions, for example to ignore mouse-enter events when changing group in the case of the x11 backend. This commit uses this mechanism for a similar reason for the wayland backend: to perform a series of operations which we can gather into pending state changes. We then listen to the ack-configure event on windows to wait until all windows that were involved in that state change have acked. When the last one acks (or when 200ms have passed, whichever comes first), we can then apply all of those state changes simultaneously.
These windows are not ordered and can't be pending more than once so a set is better form.
This commit does a few things with the goal of having `Window.place()` as the one and *only* way to change a window's x, y, width or height. This lets the backend have a greater degree of control over window reconfiguring, and is required for truly atomic state changes in the Wayland backend, as well as correctly sending configure notifys to windows in the X11 backend. Changes: - All arguments to `Window.place` are optional keyword args. - The X11 `Window.place` correctly sends configure notify events when the window is moved but not resized. - The Wayland `Window.place` only sends a resize request to the client when either `width` or `height` is passed. - `Window._enablefloating` and `Window._reconfigure_floating`, which exist in both backends, have been collapsed into one (the latter). - All instances where `Window.{x,y,width,height}` were set directly have been adjusted to instead pass the new value into `Window.place()`. - All instances where `bordercolor=None` was passed to `Window.place` have been removed. - All instances where the arguments passed to `Window.place` were directly retrieved from that window's property have been removed (See e.g. the change in scratchpad.py). The intended usage is now to do something like `place(x=x, y=y)` or `place(width=width, height=height)` if these are the only changes, rather than directly setting those properties. Note that though these properties should eventually become read-only by removing the setters, the setters remain usable, logging a deprecation notice.
While this makes little difference in regular usage, this ensures that tests do not fail due to pending geometry-related events waiting on the core's event queue.
If a window is being resized or moved, geometry changes are added to the queue of pending changes so that they can all be applied atomically. This commit includes border width and colors in this process, if they were provided to `Window.place()`. This prevents border changes happening out of step with other layout changes, which results in a strange state for a small number of frames while waiting for windows to ack, where a window's border has changed (possibly causing it to shift diagonally) but the remaining layout changes are still pending.
Thanks for the detailed pr! I am currently running this and it's really nice to see my terminals not have the dimension 'flicker'.
Could you give me a reliably way to reproduce this (if there is one). I am currently trying it out and I can't seem to get in this state
Firefox works for me. I observe that firefox still goes to a default dimension for a second (like half my screen) and then goes to the whole screen in a layout with it as the only window. Is this something you observe or is firefox completely broken for you now? Edit: just to add, with sway, the applications also kind of have the whole "dimension is loading" thing, but the border is drawn in the correct dimension the whole time, just the (visible) window inside the border takes a second to fully correct to the dimension of the border around it |
Here is a video of it happening. Note the firefox window opens on a different group from the current, and it is launched via a keybinding. Then I change to that group, show the small window highlighted by some double borders, and then when I open a recording.mp4
The problem with this is that it doesn't seem very reliable, so I will play around with things to see if I can find a pattern. The 200ms cut-off thing is literally a race so maybe it happens when foot.mp4 |
I am getting occasional problems with dragging floating windows around, and also sometimes segfaults that crash Qtile back to TTY. Nothing reliable yet though so not much else to report. |
Now that is really weird indeed. I do not seem to have this issue :(. I've had weird firefox profiles before. Does it work with that profile on e.g. sway?
Hmmmmmm, this is funny because I just had a segfault suddenly when reading that and opening a foot terminal, are you hacking me 👀
Interesting thanks, I hope I can get to the bottom of this. I will do some debugging and try various things this week and I will report back when I have some news. |
Firefox runs and is rendered perfectly on sway with this profile so I guess it is a bug here. If I return the
At least the segfaults are reproducible across machines then 😆 I did just get one when trying to drag a nested session launched via the |
I think maybe using ack_configure is not the way to go and instead we should be looking at the xdg_surface's configure_serial upon commit. I'm not entirely sure what difference this might have, but sway seems to do this. It's likely I've misunderstood the ack-configure thing. Also a change that may or may not be important: we set up some listeners in |
Okay that clears it up. I will look into it
Hopefully we find a good way to reproduce the crash, race conditions can be very hard to debug :(
I also am not sure what the difference is. Edit: Looking at e.g. river, they also set the |
Something that we do not do at all, which we could if it helps, is to remove listeners when unmapping and return them again upon mapping, rather than just setting them up at the first map event and then leaving them. |
Yeah I noticed this in the river code. We can make a separate pr to clean up these listeners or do it here? |
Up to you - if it makes it easier to do it piece by piece then that's fine. |
Looks like I can't give you access to edit this branch directly, so feel free to create a PR if you have updates and we can close this one in favour of that one. |
Gotcha! I have been procrastinating doing other issues, but I will get to this soon. |
No rush whatsoever, in your own time! |
Sorry for taking so long on this. I have actually been making a toy wayland compositor in c++ in my free time as I want to more thoroughly understand wayland. I will get back to this when I have a good understanding of what the best way to do this is |
No worries at all 😄 sounds great! |
Another relevant issue: #2911 |
This PR is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 30 days. |
This PR is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 30 days. |
go away bot, I want to pick this up eventually :D |
This PR is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 30 days. |
@m-col should we close this or do you think we can rebase this on top of 0.16 pr? |
This is a work in progress draft for some collaborative work with @jwijenbergh.
There are two main changes across these 5 commits:
Window.place()
and its use within the codebase. This becomes the single, exclusive point of entry for making geometric state changes on windows.Window.{x,y,width,height}
are no longer intended to be used as direct setters, though they will continue to work (logging deprecation warnings). To reduce code duplication, all of its arguments have become kwargs so you can do e.g.window.place(borderwidth=4)
, and that would be the canonical way to change borderwidth. This makes it much easier to control state changes on windows and group them for...Core.masked()
context manager so that configure requests sent to windows can be saved in a pending queue, and only when the final window is acked are the state changes applied simultaneously on all involved windows.The (intended) effect is that every frame is rendered perfectly, addressing #2544. Noticably this means windows will not appear with the wrong geometry for a frame before fixing themselves, and adding/removing windows from a tiled layout results in the tiled layout changing atomically without any windows lagging their geomtry change for very short (but noticable) amount of time.
Current issues that need resolving: