aboutsummaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-05-04 11:10:02 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-05-04 11:10:02 +0400
commit73cc0079d628e66b1d64168ed1a10b13b23ab5d0 (patch)
tree168aa5d885c2061c8ec9090e1cd46b865a6f2a42 /src/layout
parent69aeba2a4d93b34eb24319c3694ad354dc608a87 (diff)
downloadniri-73cc0079d628e66b1d64168ed1a10b13b23ab5d0.tar.gz
niri-73cc0079d628e66b1d64168ed1a10b13b23ab5d0.tar.bz2
niri-73cc0079d628e66b1d64168ed1a10b13b23ab5d0.zip
Split update_render_elements() from advance_animations()
advance_animations() is called from places like input, whereas update_render_elements() is strictly for rendering.
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/focus_ring.rs189
-rw-r--r--src/layout/mod.rs33
-rw-r--r--src/layout/monitor.rs33
-rw-r--r--src/layout/tile.rs62
-rw-r--r--src/layout/workspace.rs55
5 files changed, 208 insertions, 164 deletions
diff --git a/src/layout/focus_ring.rs b/src/layout/focus_ring.rs
index a0d0acfe..b198e838 100644
--- a/src/layout/focus_ring.rs
+++ b/src/layout/focus_ring.rs
@@ -1,9 +1,8 @@
-use std::cell::RefCell;
use std::cmp::{max, min};
use std::iter::zip;
use arrayvec::ArrayVec;
-use niri_config::{CornerRadius, GradientRelativeTo};
+use niri_config::{CornerRadius, Gradient, GradientRelativeTo};
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
use smithay::backend::renderer::element::Kind;
use smithay::utils::{Logical, Point, Rectangle, Scale, Size};
@@ -17,11 +16,10 @@ pub struct FocusRing {
buffers: [SolidColorBuffer; 8],
locations: [Point<i32, Logical>; 8],
sizes: [Size<i32, Logical>; 8],
- borders: RefCell<[BorderRenderElement; 8]>,
+ borders: [BorderRenderElement; 8],
full_size: Size<i32, Logical>,
- is_active: bool,
is_border: bool,
- radius: CornerRadius,
+ use_border_shader: bool,
config: niri_config::FocusRing,
}
@@ -40,9 +38,8 @@ impl FocusRing {
sizes: Default::default(),
borders: Default::default(),
full_size: Default::default(),
- is_active: false,
is_border: false,
- radius: Default::default(),
+ use_border_shader: false,
config,
}
}
@@ -52,18 +49,64 @@ impl FocusRing {
}
pub fn update_shaders(&mut self) {
- let mut borders = self.borders.borrow_mut();
- for elem in &mut *borders {
+ for elem in &mut self.borders {
elem.damage_all();
}
}
- pub fn update(&mut self, win_size: Size<i32, Logical>, is_border: bool, radius: CornerRadius) {
+ pub fn update_render_elements(
+ &mut self,
+ win_size: Size<i32, Logical>,
+ is_active: bool,
+ is_border: bool,
+ view_rect: Rectangle<i32, Logical>,
+ radius: CornerRadius,
+ ) {
let width = i32::from(self.config.width);
self.full_size = win_size + Size::from((width * 2, width * 2));
+ let color = if is_active {
+ self.config.active_color
+ } else {
+ self.config.inactive_color
+ };
+
+ for buf in &mut self.buffers {
+ buf.set_color(color.into());
+ }
+
let radius = radius.fit_to(self.full_size.w as f32, self.full_size.h as f32);
+ let gradient = if is_active {
+ self.config.active_gradient
+ } else {
+ self.config.inactive_gradient
+ };
+
+ self.use_border_shader = radius != CornerRadius::default() || gradient.is_some();
+
+ // Set the defaults for solid color + rounded corners.
+ let gradient = gradient.unwrap_or(Gradient {
+ from: color,
+ to: color,
+ angle: 0,
+ relative_to: GradientRelativeTo::Window,
+ });
+
+ let full_rect = Rectangle::from_loc_and_size((-width, -width), self.full_size);
+ let gradient_area = match gradient.relative_to {
+ GradientRelativeTo::Window => full_rect,
+ GradientRelativeTo::WorkspaceView => view_rect,
+ };
+
+ let rounded_corner_border_width = if self.is_border {
+ // HACK: increase the border width used for the inner rounded corners a tiny bit to
+ // reduce background bleed.
+ width as f32 + 0.5
+ } else {
+ 0.
+ };
+
if is_border {
let top_left = max(width, radius.top_left.ceil() as i32);
let top_right = min(
@@ -121,28 +164,40 @@ impl FocusRing {
for (buf, size) in zip(&mut self.buffers, self.sizes) {
buf.resize(size);
}
+
+ for (border, (loc, size)) in zip(&mut self.borders, zip(self.locations, self.sizes)) {
+ border.update(
+ size,
+ Rectangle::from_loc_and_size(gradient_area.loc - loc, gradient_area.size),
+ gradient.from.into(),
+ gradient.to.into(),
+ ((gradient.angle as f32) - 90.).to_radians(),
+ Rectangle::from_loc_and_size(full_rect.loc - loc, full_rect.size),
+ rounded_corner_border_width,
+ radius,
+ );
+ }
} else {
self.sizes[0] = self.full_size;
self.buffers[0].resize(self.sizes[0]);
self.locations[0] = Point::from((-width, -width));
- }
-
- self.is_border = is_border;
- self.radius = radius;
- }
- pub fn set_active(&mut self, is_active: bool) {
- let color = if is_active {
- self.config.active_color.into()
- } else {
- self.config.inactive_color.into()
- };
-
- for buf in &mut self.buffers {
- buf.set_color(color);
+ self.borders[0].update(
+ self.sizes[0],
+ Rectangle::from_loc_and_size(
+ gradient_area.loc - self.locations[0],
+ gradient_area.size,
+ ),
+ gradient.from.into(),
+ gradient.to.into(),
+ ((gradient.angle as f32) - 90.).to_radians(),
+ Rectangle::from_loc_and_size(full_rect.loc - self.locations[0], full_rect.size),
+ rounded_corner_border_width,
+ radius,
+ );
}
- self.is_active = is_active;
+ self.is_border = is_border;
}
pub fn render(
@@ -150,7 +205,6 @@ impl FocusRing {
renderer: &mut impl NiriRenderer,
location: Point<i32, Logical>,
scale: Scale<f64>,
- view_size: Size<i32, Logical>,
) -> impl Iterator<Item = FocusRingRenderElement> {
let mut rv = ArrayVec::<_, 8>::new();
@@ -165,75 +219,12 @@ impl FocusRing {
return rv.into_iter();
}
- let gradient = if self.is_active {
- self.config.active_gradient
- } else {
- self.config.inactive_gradient
- };
- let color = if self.is_active {
- self.config.active_color
- } else {
- self.config.inactive_color
- };
-
- let offset = Point::from((border_width, border_width));
- let full_rect = Rectangle::from_loc_and_size(location - offset, self.full_size);
- let view_rect = Rectangle::from_loc_and_size((0, 0), view_size);
-
- let border_width = if self.is_border {
- // HACK: increase the border width used for the inner rounded corners a tiny bit to
- // reduce background bleed.
- border_width as f32 + 0.5 / scale.x as f32
- } else {
- 0.
- };
let has_border_shader = BorderRenderElement::has_shader(renderer);
- let mut borders = self.borders.borrow_mut();
-
- let mut push = |buffer,
- border: &mut BorderRenderElement,
- location: Point<i32, Logical>,
- size: Size<i32, Logical>| {
- let full_rect = Rectangle::from_loc_and_size(full_rect.loc - location, full_rect.size);
- let view_rect = Rectangle::from_loc_and_size(view_rect.loc - location, view_rect.size);
-
- let elem = if has_border_shader {
- if let Some(gradient) = gradient {
- let gradient_area = match gradient.relative_to {
- GradientRelativeTo::Window => full_rect,
- GradientRelativeTo::WorkspaceView => view_rect,
- };
- border.update(
- size,
- gradient_area,
- gradient.from.into(),
- gradient.to.into(),
- ((gradient.angle as f32) - 90.).to_radians(),
- full_rect,
- border_width,
- self.radius,
- );
- Some(border.clone().with_location(location).into())
- } else if self.radius != CornerRadius::default() {
- border.update(
- size,
- full_rect,
- color.into(),
- color.into(),
- 0.,
- full_rect,
- border_width,
- self.radius,
- );
- Some(border.clone().with_location(location).into())
- } else {
- None
- }
- } else {
- None
- };
- let elem = elem.unwrap_or_else(|| {
+ let mut push = |buffer, border: &BorderRenderElement, location: Point<i32, Logical>| {
+ let elem = if self.use_border_shader && has_border_shader {
+ border.clone().with_location(location).into()
+ } else {
SolidColorRenderElement::from_buffer(
buffer,
location.to_physical_precise_round(scale),
@@ -242,23 +233,19 @@ impl FocusRing {
Kind::Unspecified,
)
.into()
- });
+ };
rv.push(elem);
};
if self.is_border {
- for ((buf, border), (loc, size)) in zip(
- zip(&self.buffers, &mut *borders),
- zip(self.locations, self.sizes),
- ) {
- push(buf, border, location + loc, size);
+ for ((buf, border), loc) in zip(zip(&self.buffers, &self.borders), self.locations) {
+ push(buf, border, location + loc);
}
} else {
push(
&self.buffers[0],
- &mut borders[0],
+ &self.borders[0],
location + self.locations[0],
- self.sizes[0],
);
}
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index b670b9f5..b93dfb4d 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -1354,23 +1354,40 @@ impl<W: LayoutElement> Layout<W> {
let _span = tracy_client::span!("Layout::advance_animations");
match &mut self.monitor_set {
- MonitorSet::Normal {
- monitors,
- active_monitor_idx,
- ..
- } => {
- for (idx, mon) in monitors.iter_mut().enumerate() {
- mon.advance_animations(current_time, idx == *active_monitor_idx);
+ MonitorSet::Normal { monitors, .. } => {
+ for mon in monitors {
+ mon.advance_animations(current_time);
}
}
MonitorSet::NoOutputs { workspaces, .. } => {
for ws in workspaces {
- ws.advance_animations(current_time, false);
+ ws.advance_animations(current_time);
}
}
}
}
+ pub fn update_render_elements(&mut self, output: &Output) {
+ let _span = tracy_client::span!("Layout::update_render_elements");
+
+ let MonitorSet::Normal {
+ monitors,
+ active_monitor_idx,
+ ..
+ } = &mut self.monitor_set
+ else {
+ error!("update_render_elements called with no monitors");
+ return;
+ };
+
+ for (idx, mon) in monitors.iter_mut().enumerate() {
+ if mon.output == *output {
+ mon.update_render_elements(idx == *active_monitor_idx);
+ return;
+ }
+ }
+ }
+
pub fn update_shaders(&mut self) {
match &mut self.monitor_set {
MonitorSet::Normal { monitors, .. } => {
diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs
index f1e8d542..8d695139 100644
--- a/src/layout/monitor.rs
+++ b/src/layout/monitor.rs
@@ -523,7 +523,7 @@ impl<W: LayoutElement> Monitor<W> {
Some(column.tiles[column.active_tile_idx].window())
}
- pub fn advance_animations(&mut self, current_time: Duration, is_active: bool) {
+ pub fn advance_animations(&mut self, current_time: Duration) {
if let Some(WorkspaceSwitch::Animation(anim)) = &mut self.workspace_switch {
anim.set_current_time(current_time);
if anim.is_done() {
@@ -533,7 +533,7 @@ impl<W: LayoutElement> Monitor<W> {
}
for ws in &mut self.workspaces {
- ws.advance_animations(current_time, is_active);
+ ws.advance_animations(current_time);
}
}
@@ -552,6 +552,35 @@ impl<W: LayoutElement> Monitor<W> {
.any(|ws| ws.are_transitions_ongoing())
}
+ pub fn update_render_elements(&mut self, is_active: bool) {
+ match &self.workspace_switch {
+ Some(switch) => {
+ let render_idx = switch.current_idx();
+ let before_idx = render_idx.floor();
+ let after_idx = render_idx.ceil();
+
+ if after_idx < 0. || before_idx as usize >= self.workspaces.len() {
+ return;
+ }
+
+ let after_idx = after_idx as usize;
+ if after_idx < self.workspaces.len() {
+ self.workspaces[after_idx].update_render_elements(is_active);
+
+ if before_idx < 0. {
+ return;
+ }
+ }
+
+ let before_idx = before_idx as usize;
+ self.workspaces[before_idx].update_render_elements(is_active);
+ }
+ None => {
+ self.workspaces[self.active_workspace_idx].update_render_elements(is_active);
+ }
+ }
+ }
+
pub fn update_config(&mut self, options: Rc<Options>) {
for ws in &mut self.workspaces {
ws.update_config(options.clone());
diff --git a/src/layout/tile.rs b/src/layout/tile.rs
index b5b40df0..be9829a9 100644
--- a/src/layout/tile.rs
+++ b/src/layout/tile.rs
@@ -201,7 +201,7 @@ impl<W: LayoutElement> Tile<W> {
self.rounded_corner_damage.set_size(window_size);
}
- pub fn advance_animations(&mut self, current_time: Duration, is_active: bool) {
+ pub fn advance_animations(&mut self, current_time: Duration) {
if let Some(anim) = &mut self.open_animation {
anim.set_current_time(current_time);
if anim.is_done() {
@@ -228,6 +228,17 @@ impl<W: LayoutElement> Tile<W> {
self.move_y_animation = None;
}
}
+ }
+
+ pub fn are_animations_ongoing(&self) -> bool {
+ self.open_animation.is_some()
+ || self.resize_animation.is_some()
+ || self.move_x_animation.is_some()
+ || self.move_y_animation.is_some()
+ }
+
+ pub fn update(&mut self, is_active: bool, mut view_rect: Rectangle<i32, Logical>) {
+ view_rect.loc -= self.render_offset();
let rules = self.window.rules();
@@ -244,12 +255,16 @@ impl<W: LayoutElement> Tile<W> {
radius.expanded_by(border_width as f32)
})
};
- self.border.update(
+ self.border.update_render_elements(
self.animated_window_size(),
+ is_active,
!draw_border_with_background,
+ Rectangle::from_loc_and_size(
+ view_rect.loc - Point::from((border_width, border_width)),
+ view_rect.size,
+ ),
radius,
);
- self.border.set_active(is_active);
let draw_focus_ring_with_background = if self.effective_border_width().is_some() {
false
@@ -264,19 +279,13 @@ impl<W: LayoutElement> Tile<W> {
rules.geometry_corner_radius.unwrap_or_default()
}
.expanded_by(self.focus_ring.width() as f32);
- self.focus_ring.update(
+ self.focus_ring.update_render_elements(
self.animated_tile_size(),
+ is_active,
!draw_focus_ring_with_background,
+ view_rect,
radius,
);
- self.focus_ring.set_active(is_active);
- }
-
- pub fn are_animations_ongoing(&self) -> bool {
- self.open_animation.is_some()
- || self.resize_animation.is_some()
- || self.move_x_animation.is_some()
- || self.move_y_animation.is_some()
}
pub fn render_offset(&self) -> Point<i32, Logical> {
@@ -568,7 +577,6 @@ impl<W: LayoutElement> Tile<W> {
renderer: &mut R,
location: Point<i32, Logical>,
scale: Scale<f64>,
- view_size: Size<i32, Logical>,
focus_ring: bool,
target: RenderTarget,
) -> impl Iterator<Item = TileRenderElement<R>> {
@@ -766,19 +774,14 @@ impl<W: LayoutElement> Tile<W> {
let elem = self.effective_border_width().map(|width| {
self.border
- .render(
- renderer,
- location + Point::from((width, width)),
- scale,
- view_size,
- )
+ .render(renderer, location + Point::from((width, width)), scale)
.map(Into::into)
});
let rv = rv.chain(elem.into_iter().flatten());
let elem = focus_ring.then(|| {
self.focus_ring
- .render(renderer, location, scale, view_size)
+ .render(renderer, location, scale)
.map(Into::into)
});
rv.chain(elem.into_iter().flatten())
@@ -789,7 +792,6 @@ impl<W: LayoutElement> Tile<W> {
renderer: &mut R,
location: Point<i32, Logical>,
scale: Scale<f64>,
- view_size: Size<i32, Logical>,
focus_ring: bool,
target: RenderTarget,
) -> impl Iterator<Item = TileRenderElement<R>> {
@@ -797,8 +799,7 @@ impl<W: LayoutElement> Tile<W> {
if let Some(anim) = &self.open_animation {
let renderer = renderer.as_gles_renderer();
- let elements =
- self.render_inner(renderer, location, scale, view_size, focus_ring, target);
+ let elements = self.render_inner(renderer, location, scale, focus_ring, target);
let elements = elements.collect::<Vec<TileRenderElement<_>>>();
let elem = OffscreenRenderElement::new(
@@ -826,31 +827,24 @@ impl<W: LayoutElement> Tile<W> {
} else {
self.window().set_offscreen_element_id(None);
- let elements =
- self.render_inner(renderer, location, scale, view_size, focus_ring, target);
+ let elements = self.render_inner(renderer, location, scale, focus_ring, target);
None.into_iter().chain(Some(elements).into_iter().flatten())
}
}
- pub fn store_unmap_snapshot_if_empty(
- &self,
- renderer: &mut GlesRenderer,
- scale: Scale<f64>,
- view_size: Size<i32, Logical>,
- ) {
+ pub fn store_unmap_snapshot_if_empty(&self, renderer: &mut GlesRenderer, scale: Scale<f64>) {
let mut snapshot = self.unmap_snapshot.borrow_mut();
if snapshot.is_some() {
return;
}
- *snapshot = Some(self.render_snapshot(renderer, scale, view_size));
+ *snapshot = Some(self.render_snapshot(renderer, scale));
}
fn render_snapshot(
&self,
renderer: &mut GlesRenderer,
scale: Scale<f64>,
- view_size: Size<i32, Logical>,
) -> TileRenderSnapshot {
let _span = tracy_client::span!("Tile::render_snapshot");
@@ -858,7 +852,6 @@ impl<W: LayoutElement> Tile<W> {
renderer,
Point::from((0, 0)),
scale,
- view_size,
false,
RenderTarget::Output,
);
@@ -868,7 +861,6 @@ impl<W: LayoutElement> Tile<W> {
renderer,
Point::from((0, 0)),
scale,
- view_size,
false,
RenderTarget::Screencast,
);
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index 3205d82b..05d5f280 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -289,7 +289,7 @@ impl<W: LayoutElement> Workspace<W> {
self.id
}
- pub fn advance_animations(&mut self, current_time: Duration, is_active: bool) {
+ pub fn advance_animations(&mut self, current_time: Duration) {
if let Some(ViewOffsetAdjustment::Animation(anim)) = &mut self.view_offset_adj {
anim.set_current_time(current_time);
self.view_offset = anim.value().round() as i32;
@@ -300,9 +300,8 @@ impl<W: LayoutElement> Workspace<W> {
self.view_offset = gesture.current_view_offset.round() as i32;
}
- for (col_idx, col) in self.columns.iter_mut().enumerate() {
- let is_active = is_active && col_idx == self.active_column_idx;
- col.advance_animations(current_time, is_active);
+ for col in &mut self.columns {
+ col.advance_animations(current_time);
}
self.closing_windows.retain_mut(|closing| {
@@ -325,6 +324,16 @@ impl<W: LayoutElement> Workspace<W> {
|| !self.closing_windows.is_empty()
}
+ pub fn update_render_elements(&mut self, is_active: bool) {
+ let mut view_rect = Rectangle::from_loc_and_size((self.view_pos(), 0), self.view_size);
+
+ for (col_idx, col) in self.columns.iter_mut().enumerate() {
+ let is_active = is_active && col_idx == self.active_column_idx;
+ col.update_render_elements(is_active, view_rect);
+ view_rect.loc.x -= col.width() + self.options.gaps;
+ }
+ }
+
pub fn update_config(&mut self, options: Rc<Options>) {
for column in &mut self.columns {
column.update_config(options.clone());
@@ -1198,7 +1207,7 @@ impl<W: LayoutElement> Workspace<W> {
.map(|o| Scale::from(o.current_scale().fractional_scale()))
.unwrap_or(Scale::from(1.));
- tile.store_unmap_snapshot_if_empty(renderer, output_scale, self.view_size);
+ tile.store_unmap_snapshot_if_empty(renderer, output_scale);
}
pub fn clear_unmap_snapshot(&mut self, window: &W::Id) {
@@ -1947,15 +1956,8 @@ impl<W: LayoutElement> Workspace<W> {
first = false;
rv.extend(
- tile.render(
- renderer,
- tile_pos,
- output_scale,
- self.view_size,
- focus_ring,
- target,
- )
- .map(Into::into),
+ tile.render(renderer, tile_pos, output_scale, focus_ring, target)
+ .map(Into::into),
);
}
@@ -2298,7 +2300,7 @@ impl<W: LayoutElement> Column<W> {
self.update_tile_sizes(true);
}
- pub fn advance_animations(&mut self, current_time: Duration, is_active: bool) {
+ pub fn advance_animations(&mut self, current_time: Duration) {
match &mut self.move_animation {
Some(anim) => {
anim.set_current_time(current_time);
@@ -2309,9 +2311,8 @@ impl<W: LayoutElement> Column<W> {
None => (),
}
- for (tile_idx, tile) in self.tiles.iter_mut().enumerate() {
- let is_active = is_active && tile_idx == self.active_tile_idx;
- tile.advance_animations(current_time, is_active);
+ for tile in &mut self.tiles {
+ tile.advance_animations(current_time);
}
}
@@ -2319,6 +2320,24 @@ impl<W: LayoutElement> Column<W> {
self.move_animation.is_some() || self.tiles.iter().any(Tile::are_animations_ongoing)
}
+ pub fn update_render_elements(
+ &mut self,
+ is_active: bool,
+ mut view_rect: Rectangle<i32, Logical>,
+ ) {
+ view_rect.loc -= self.render_offset();
+
+ if !self.is_fullscreen {
+ view_rect.loc.y -= self.working_area.loc.y + self.options.gaps;
+ }
+
+ for (tile_idx, tile) in self.tiles.iter_mut().enumerate() {
+ let is_active = is_active && tile_idx == self.active_tile_idx;
+ tile.update(is_active, view_rect);
+ view_rect.loc.y -= tile.tile_size().h + self.options.gaps;
+ }
+ }
+
pub fn render_offset(&self) -> Point<i32, Logical> {
let mut offset = Point::from((0., 0.));