aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-09-24 18:10:43 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-09-24 18:11:20 +0400
commitf58e56d65ab0c41facc72b75e8a85d64b54963ef (patch)
tree87659a74ec20e00a274cc1f488f82fb598d0fcef /src
parent51df1aba019dde896d32f32d7a8b21b71064ada3 (diff)
downloadniri-f58e56d65ab0c41facc72b75e8a85d64b54963ef.tar.gz
niri-f58e56d65ab0c41facc72b75e8a85d64b54963ef.tar.bz2
niri-f58e56d65ab0c41facc72b75e8a85d64b54963ef.zip
Add focus rings
Diffstat (limited to 'src')
-rw-r--r--src/layout.rs78
-rw-r--r--src/niri.rs3
2 files changed, 60 insertions, 21 deletions
diff --git a/src/layout.rs b/src/layout.rs
index e5caa107..76afaf0e 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -33,17 +33,20 @@ use std::cmp::{max, min};
use std::mem;
use std::time::Duration;
+use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;
use smithay::backend::renderer::element::utils::{
CropRenderElement, Relocate, RelocateRenderElement,
};
-use smithay::backend::renderer::element::AsRenderElements;
+use smithay::backend::renderer::element::{AsRenderElements, Kind};
use smithay::backend::renderer::gles::GlesRenderer;
+use smithay::backend::renderer::ImportAll;
use smithay::desktop::space::SpaceElement;
use smithay::desktop::Window;
use smithay::output::Output;
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel;
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
+use smithay::render_elements;
use smithay::utils::{Logical, Point, Rectangle, Scale, Size};
use smithay::wayland::compositor::{with_states, SurfaceData};
use smithay::wayland::dmabuf::DmabufFeedback;
@@ -52,6 +55,9 @@ use smithay::wayland::shell::xdg::SurfaceCachedState;
use crate::animation::Animation;
const PADDING: i32 = 16;
+const FOCUS_RING_PADDING: i32 = 4;
+const FOCUS_RING_ACTIVE_COLOR: [f32; 4] = [0.5, 0.8, 1.0, 1.0];
+const FOCUS_RING_INACTIVE_COLOR: [f32; 4] = [0.3, 0.3, 0.3, 1.0];
const WIDTH_PROPORTIONS: [ColumnWidth; 3] = [
ColumnWidth::Proportion(1. / 3.),
ColumnWidth::Proportion(0.5),
@@ -61,7 +67,12 @@ const WIDTH_PROPORTIONS: [ColumnWidth; 3] = [
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OutputId(String);
-pub type WorkspaceRenderElement<R> = WaylandSurfaceRenderElement<R>;
+render_elements! {
+ #[derive(Debug)]
+ pub WorkspaceRenderElement<R> where R: ImportAll;
+ Wayland = WaylandSurfaceRenderElement<R>,
+ FocusRing = SolidColorRenderElement,
+}
pub type MonitorRenderElement<R> =
RelocateRenderElement<CropRenderElement<WorkspaceRenderElement<R>>>;
@@ -140,6 +151,9 @@ pub struct Workspace<W: LayoutElement> {
/// Index of the currently active column, if any.
active_column_idx: usize,
+ /// The solid color buffer for the focus ring.
+ focus_ring: SolidColorBuffer,
+
/// Offset of the view computed from the active column.
view_offset: i32,
@@ -643,16 +657,6 @@ impl<W: LayoutElement> MonitorSet<W> {
monitors.iter().find(|monitor| &monitor.output == output)
}
- pub fn monitor_for_output_mut(&mut self, output: &Output) -> Option<&mut Monitor<W>> {
- let MonitorSet::Normal { monitors, .. } = self else {
- return None;
- };
-
- monitors
- .iter_mut()
- .find(|monitor| &monitor.output == output)
- }
-
pub fn outputs(&self) -> impl Iterator<Item = &Output> + '_ {
let monitors = if let MonitorSet::Normal { monitors, .. } = self {
&monitors[..]
@@ -852,14 +856,18 @@ impl<W: LayoutElement> MonitorSet<W> {
pub fn advance_animations(&mut self, current_time: Duration) {
match self {
- MonitorSet::Normal { monitors, .. } => {
- for mon in monitors {
- mon.advance_animations(current_time);
+ MonitorSet::Normal {
+ monitors,
+ active_monitor_idx,
+ ..
+ } => {
+ for (idx, mon) in monitors.iter_mut().enumerate() {
+ mon.advance_animations(current_time, idx == *active_monitor_idx);
}
}
MonitorSet::NoOutputs(workspaces) => {
for ws in workspaces {
- ws.advance_animations(current_time);
+ ws.advance_animations(current_time, false);
}
}
}
@@ -1213,7 +1221,7 @@ impl<W: LayoutElement> Monitor<W> {
Some(&column.windows[column.active_window_idx])
}
- pub fn advance_animations(&mut self, current_time: Duration) {
+ pub fn advance_animations(&mut self, current_time: Duration, is_active: bool) {
if let Some(anim) = &mut self.workspace_idx_anim {
anim.set_current_time(current_time);
if anim.is_done() {
@@ -1223,7 +1231,7 @@ impl<W: LayoutElement> Monitor<W> {
}
for ws in &mut self.workspaces {
- ws.advance_animations(current_time);
+ ws.advance_animations(current_time, is_active);
}
}
@@ -1311,6 +1319,7 @@ impl<W: LayoutElement> Workspace<W> {
output: Some(output),
columns: vec![],
active_column_idx: 0,
+ focus_ring: SolidColorBuffer::new((0, 0), FOCUS_RING_ACTIVE_COLOR),
view_offset: 0,
view_offset_anim: None,
activate_prev_column_on_removal: false,
@@ -1324,13 +1333,14 @@ impl<W: LayoutElement> Workspace<W> {
view_size: Size::from((1280, 720)),
columns: vec![],
active_column_idx: 0,
+ focus_ring: SolidColorBuffer::new((0, 0), FOCUS_RING_ACTIVE_COLOR),
view_offset: 0,
view_offset_anim: None,
activate_prev_column_on_removal: false,
}
}
- pub fn advance_animations(&mut self, current_time: Duration) {
+ pub fn advance_animations(&mut self, current_time: Duration, is_active: bool) {
match &mut self.view_offset_anim {
Some(anim) => {
anim.set_current_time(current_time);
@@ -1341,6 +1351,21 @@ impl<W: LayoutElement> Workspace<W> {
}
None => (),
}
+
+ // This shall one day become a proper animation.
+ if !self.columns.is_empty() {
+ let col = &self.columns[self.active_column_idx];
+ let active_win = &col.windows[col.active_window_idx];
+ let geom = active_win.geometry();
+ self.focus_ring
+ .resize(geom.size + Size::from((FOCUS_RING_PADDING * 2, FOCUS_RING_PADDING * 2)));
+
+ self.focus_ring.set_color(if is_active {
+ FOCUS_RING_ACTIVE_COLOR
+ } else {
+ FOCUS_RING_INACTIVE_COLOR
+ });
+ }
}
fn windows(&self) -> impl Iterator<Item = &W> + '_ {
@@ -1882,6 +1907,8 @@ impl Workspace<Window> {
// FIXME: fullscreen windows are missing left padding
win_pos.x -= PADDING;
}
+
+ // Draw the window itself.
rv.extend(active_win.render_elements(
renderer,
win_pos.to_physical_precise_round(output_scale),
@@ -1889,6 +1916,19 @@ impl Workspace<Window> {
1.,
));
+ // Draw the focus ring.
+ rv.push(
+ SolidColorRenderElement::from_buffer(
+ &self.focus_ring,
+ (win_pos + geom.loc - Point::from((FOCUS_RING_PADDING, FOCUS_RING_PADDING)))
+ .to_physical_precise_round(output_scale),
+ output_scale,
+ 1.,
+ Kind::Unspecified,
+ )
+ .into(),
+ );
+
let mut x = PADDING;
for col in &self.columns {
let mut y = PADDING;
diff --git a/src/niri.rs b/src/niri.rs
index 0ae5e096..35346bd7 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -951,8 +951,7 @@ impl Niri {
assert!(!state.waiting_for_vblank);
// Advance the animations.
- let mon = self.monitor_set.monitor_for_output_mut(output).unwrap();
- mon.advance_animations(presentation_time);
+ self.monitor_set.advance_animations(presentation_time);
// Render the elements.
let elements = self.render(backend.renderer(), output, true);