Our current rendering code constructs and returns complex
`-> impl Iterator<Item = SomeRenderElement>` types that are collected
into a vector at the top level Niri::render(). This causes some
problems:
- It's hard to write logic around returning iterators. Especially things
like conditions, since the returned iterator must have a single type,
you can't branch and return different iterators. This will be solved
by gen fn but alas it's not here yet.
- In many cases, the returned `-> impl Iterator` will borrow from &self
leading to complex lifetimes. In certain cases, it is also desirable
for it to borrow the &mut NiriRenderer, which causes a lot of issues
because it's exclusive (&mut).
- Sometimes those issues are too hard to deal with, leading to the
escape hatch of allocating and returning a temporary
Vec<SomeRenderElement>, like in
Scrolling/FloatingSpace::render_elements(). These allocations are
unfortunate because they are not really necessary.
- It's impossible to use some downstream combinators with this
`-> impl Iterator` approach, leading to functions like Smithay's
render_elements_from_surface_tree() returning a Vec. This is extra
unfortunate because it results in a temporary allocation per Wayland
toplevel/popup.
- It's hard to properly create profiling spans for the rendering
functions since the spans are dropped when the (lazy) iterator is
returned and not when all the code actually completes.
- The code compiles down to complex state machines in generated iterator
types with logic located in Iterator::next(), which makes it annoying
to follow in debuggers and profiling tools.
This refactor changes the code to push-based iteration: rendering
functions receive a push() closure that they call to push their render
elements. It solves all of the aforementioned problems:
- The logic becomes simpler. Just use conditionals and loops as normal.
- No borrowing and lifetimes since we're not returning anything.
- All temporary Vecs are removed because the problems they worked around
no longer exist.
- The new push_elements_from_surface_tree() helper is the same as
render_elements_from_surface_tree() but doesn't allocate a temporary
Vec since it's not necessary; the push() closure can be passed down.
- Profiling spans work normally since the function returns when it ran
all of the logic.
- The code compiles down to normal functions and calls as expected.
Generally, the iterator approach gives these advantages:
- You can wrap the returned items in the upstream logic. This is
possible in exactly the same way with the push closure.
- You can decide to cut the iterator short in the upstream logic. This
is not possible with push-based iteration, but we don't actually use
it anywhere.
I chose the push closure type to be &mut dyn FnMut(SomeRenderElement).
It's deliberately not a generic impl FnMut() to avoid duplicating the
rendering logic when it's called from several different places. But it's
still a normal closure that can capture the outside context.
While my original idea for this refactor was to simplify the logic while
getting rid of temporary Vecs, it also appears to have brought a
consistent 2-3x speedup to the whole render list construction. On an old
Eee PC laptop I even observed a 8x speedup.
The refactor also results in smaller binary size, presumably due to
removing many iterator combinators and state tracking.
When the column was added immediately to the left of the current column
and activated, the new idx would be equal to active_column_idx, which
would skip activate_column() with its variable resets.
I feel this is more intuitive compared to them doing nothing. True
maximize is kinda similar to full-width in spirit, so make the actions
behave the same.
This turned out to require quite a few changes.
We keep track of the tile resize animation progress separately now, in order to
provide a resizing black fullscreen backdrop for non-resizable windows.
The window is always rendered in the middle of the tile, which once again aids
with the resizing black fullscreen backdrop.
The backdrop itself will fade in from transparency so that it's less jarring.
The resize animation now keeps track of the fullscreen progress to deal with
the case where an unfullscreen resize is interrupted by another non-fullscreen
resize. In this case, the fullscreen progress continues animating to avoid
sudden disappearance of the fullscreen backdrop.
Some things like border visibility switch to this fullscreen progress once again
to avoid jarring appearance/disappearance.
The border radius animates in accordance with the fullscreen progress to match
the visuals.
We already did that for Tiles, but for Columns we only tracked what was
effectively pending fullscreen. We used it in several places where the current
fullscreen should've been used instead, like the tile origin or the view offset.
This commit splits the two and makes every place use the right one.
Fixes things like tiles briefly appearing at y=0 between issuing the fullscreen
command and the tile committing in response to the fullscreen configure.
* Add window sizes and positions to the IPC
* basic fixes
* report window_loc instead of window pos
* clean ups
* make scrolling indices 1-based
* add printing to niri msg windows
* don't include render offset in floating tile pos
---------
Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
* force xdg deactivation on invisable workspaces
This debug option provides a workaround for many Chromium-based chat
applications that fail to show notifications when they're active in
a workspace that's not currently visible and don't have keyboard focus
Signed-off-by: Alex Yosifov <sashomasho@gmail.com>
* fixes
---------
Signed-off-by: Alex Yosifov <sashomasho@gmail.com>
Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
Fixes cases like: do a quick movement with mouse, then hold it in-place for a
while (no events generated), then release the gesture (it uses all that
built-up speed). This also happens with DnD scroll and makes it go further than
intended.