aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2025-01-23 10:40:52 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2025-01-23 11:13:55 +0300
commita10705fb200b452802a1ba7cd47679536e0ef849 (patch)
tree7e12f0602c4652e043021392632e7e4e24ebb4fe /src
parentb01b8afa8c8f9070300243050d9790e38fd19145 (diff)
downloadniri-a10705fb200b452802a1ba7cd47679536e0ef849.tar.gz
niri-a10705fb200b452802a1ba7cd47679536e0ef849.tar.bz2
niri-a10705fb200b452802a1ba7cd47679536e0ef849.zip
Add toggle-window-rule-opacity action
Diffstat (limited to 'src')
-rw-r--r--src/input/mod.rs29
-rw-r--r--src/layout/floating.rs8
-rw-r--r--src/layout/mod.rs5
-rw-r--r--src/layout/scrolling.rs9
-rw-r--r--src/layout/tile.rs2
-rw-r--r--src/layout/workspace.rs8
-rw-r--r--src/niri.rs2
-rw-r--r--src/window/mapped.rs18
8 files changed, 79 insertions, 2 deletions
diff --git a/src/input/mod.rs b/src/input/mod.rs
index 8872df78..c9ab0b30 100644
--- a/src/input/mod.rs
+++ b/src/input/mod.rs
@@ -39,6 +39,7 @@ use self::move_grab::MoveGrab;
use self::resize_grab::ResizeGrab;
use self::spatial_movement_grab::SpatialMovementGrab;
use crate::layout::scrolling::ScrollDirection;
+use crate::layout::LayoutElement as _;
use crate::niri::State;
use crate::ui::screenshot_ui::ScreenshotUi;
use crate::utils::spawning::spawn;
@@ -1574,6 +1575,34 @@ impl State {
// FIXME: granular
self.niri.queue_redraw_all();
}
+ Action::ToggleWindowRuleOpacity => {
+ let active_window = self
+ .niri
+ .layout
+ .active_workspace_mut()
+ .and_then(|ws| ws.active_window_mut());
+ if let Some(window) = active_window {
+ if window.rules().opacity.is_some_and(|o| o != 1.) {
+ window.toggle_ignore_opacity_window_rule();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ }
+ }
+ Action::ToggleWindowRuleOpacityById(id) => {
+ let window = self
+ .niri
+ .layout
+ .workspaces_mut()
+ .find_map(|ws| ws.windows_mut().find(|w| w.id().get() == id));
+ if let Some(window) = window {
+ if window.rules().opacity.is_some_and(|o| o != 1.) {
+ window.toggle_ignore_opacity_window_rule();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ }
+ }
}
}
diff --git a/src/layout/floating.rs b/src/layout/floating.rs
index cb757d67..c6a17e30 100644
--- a/src/layout/floating.rs
+++ b/src/layout/floating.rs
@@ -365,6 +365,14 @@ impl<W: LayoutElement> FloatingSpace<W> {
.map(Tile::window)
}
+ pub fn active_window_mut(&mut self) -> Option<&mut W> {
+ let id = self.active_window_id.as_ref()?;
+ self.tiles
+ .iter_mut()
+ .find(|tile| tile.window().id() == id)
+ .map(Tile::window_mut)
+ }
+
pub fn has_window(&self, id: &W::Id) -> bool {
self.tiles.iter().any(|tile| tile.window().id() == id)
}
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index eb702c37..63bedc7f 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -190,6 +190,7 @@ pub trait LayoutElement {
fn set_active_in_column(&mut self, active: bool);
fn set_floating(&mut self, floating: bool);
fn set_bounds(&self, bounds: Size<i32, Logical>);
+ fn is_ignoring_opacity_window_rule(&self) -> bool;
fn configure_intent(&self) -> ConfigureIntent;
fn send_pending_configure(&mut self);
@@ -4347,6 +4348,10 @@ mod tests {
fn set_bounds(&self, _bounds: Size<i32, Logical>) {}
+ fn is_ignoring_opacity_window_rule(&self) -> bool {
+ false
+ }
+
fn configure_intent(&self) -> ConfigureIntent {
ConfigureIntent::CanSend
}
diff --git a/src/layout/scrolling.rs b/src/layout/scrolling.rs
index 6b8bf760..ffb51ace 100644
--- a/src/layout/scrolling.rs
+++ b/src/layout/scrolling.rs
@@ -383,6 +383,15 @@ impl<W: LayoutElement> ScrollingSpace<W> {
Some(col.tiles[col.active_tile_idx].window())
}
+ pub fn active_window_mut(&mut self) -> Option<&mut W> {
+ if self.columns.is_empty() {
+ return None;
+ }
+
+ let col = &mut self.columns[self.active_column_idx];
+ Some(col.tiles[col.active_tile_idx].window_mut())
+ }
+
pub fn active_tile_mut(&mut self) -> Option<&mut Tile<W>> {
if self.columns.is_empty() {
return None;
diff --git a/src/layout/tile.rs b/src/layout/tile.rs
index 4a5b61a9..b8d049b0 100644
--- a/src/layout/tile.rs
+++ b/src/layout/tile.rs
@@ -720,7 +720,7 @@ impl<W: LayoutElement> Tile<W> {
) -> impl Iterator<Item = TileRenderElement<R>> + 'a {
let _span = tracy_client::span!("Tile::render_inner");
- let alpha = if self.is_fullscreen {
+ let alpha = if self.is_fullscreen || self.window.is_ignoring_opacity_window_rule() {
1.
} else {
self.window.rules().opacity.unwrap_or(1.).clamp(0., 1.)
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index f4c87342..4426c264 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -406,6 +406,14 @@ impl<W: LayoutElement> Workspace<W> {
}
}
+ pub fn active_window_mut(&mut self) -> Option<&mut W> {
+ if self.floating_is_active.get() {
+ self.floating.active_window_mut()
+ } else {
+ self.scrolling.active_window_mut()
+ }
+ }
+
pub fn is_active_fullscreen(&self) -> bool {
self.scrolling.is_active_fullscreen()
}
diff --git a/src/niri.rs b/src/niri.rs
index a578ced3..687f8539 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -4597,7 +4597,7 @@ impl Niri {
let _span = tracy_client::span!("Niri::screenshot_window");
let scale = Scale::from(output.current_scale().fractional_scale());
- let alpha = if mapped.is_fullscreen() {
+ let alpha = if mapped.is_fullscreen() || mapped.is_ignoring_opacity_window_rule() {
1.
} else {
mapped.rules().opacity.unwrap_or(1.).clamp(0., 1.)
diff --git a/src/window/mapped.rs b/src/window/mapped.rs
index 207140c4..71b6c9da 100644
--- a/src/window/mapped.rs
+++ b/src/window/mapped.rs
@@ -69,6 +69,9 @@ pub struct Mapped {
/// Whether this window is floating.
is_floating: bool,
+ /// Whether this window should ignore opacity set through window rules.
+ ignore_opacity_window_rule: bool,
+
/// Buffer to draw instead of the window when it should be blocked out.
block_out_buffer: RefCell<SolidColorBuffer>,
@@ -167,6 +170,7 @@ impl Mapped {
is_focused: false,
is_active_in_column: true,
is_floating: false,
+ ignore_opacity_window_rule: false,
block_out_buffer: RefCell::new(SolidColorBuffer::new((0., 0.), [0., 0., 0., 1.])),
animate_next_configure: false,
animate_serials: Vec::new(),
@@ -192,6 +196,12 @@ impl Mapped {
return false;
}
+ // If the opacity window rule no longer makes the window semitransparent, reset the ignore
+ // flag to reduce surprises down the line.
+ if !new_rules.opacity.is_some_and(|o| o < 1.) {
+ self.ignore_opacity_window_rule = false;
+ }
+
self.rules = new_rules;
true
}
@@ -228,6 +238,10 @@ impl Mapped {
self.is_floating
}
+ pub fn toggle_ignore_opacity_window_rule(&mut self) {
+ self.ignore_opacity_window_rule = !self.ignore_opacity_window_rule;
+ }
+
pub fn set_is_focused(&mut self, is_focused: bool) {
if self.is_focused == is_focused {
return;
@@ -839,6 +853,10 @@ impl LayoutElement for Mapped {
.with_pending_state(|state| state.states.contains(xdg_toplevel::State::Fullscreen))
}
+ fn is_ignoring_opacity_window_rule(&self) -> bool {
+ self.ignore_opacity_window_rule
+ }
+
fn requested_size(&self) -> Option<Size<i32, Logical>> {
self.toplevel().with_pending_state(|state| state.size)
}