mirror of
https://github.com/YaLTeR/niri.git
synced 2025-10-06 00:23:14 +02:00
Add toggle-window-rule-opacity action
This commit is contained in:
@@ -1425,6 +1425,9 @@ pub enum Action {
|
||||
x: PositionChange,
|
||||
y: PositionChange,
|
||||
},
|
||||
ToggleWindowRuleOpacity,
|
||||
#[knuffel(skip)]
|
||||
ToggleWindowRuleOpacityById(u64),
|
||||
}
|
||||
|
||||
impl From<niri_ipc::Action> for Action {
|
||||
@@ -1623,6 +1626,10 @@ impl From<niri_ipc::Action> for Action {
|
||||
niri_ipc::Action::MoveFloatingWindow { id, x, y } => {
|
||||
Self::MoveFloatingWindowById { id, x, y }
|
||||
}
|
||||
niri_ipc::Action::ToggleWindowRuleOpacity { id: None } => Self::ToggleWindowRuleOpacity,
|
||||
niri_ipc::Action::ToggleWindowRuleOpacity { id: Some(id) } => {
|
||||
Self::ToggleWindowRuleOpacityById(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -578,6 +578,18 @@ pub enum Action {
|
||||
)]
|
||||
y: PositionChange,
|
||||
},
|
||||
/// Toggle the opacity of a window.
|
||||
#[cfg_attr(
|
||||
feature = "clap",
|
||||
clap(about = "Toggle the opacity of the focused window")
|
||||
)]
|
||||
ToggleWindowRuleOpacity {
|
||||
/// Id of the window.
|
||||
///
|
||||
/// If `None`, uses the focused window.
|
||||
#[cfg_attr(feature = "clap", arg(long))]
|
||||
id: Option<u64>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Change in window or column size.
|
||||
|
@@ -224,6 +224,10 @@ impl LayoutElement for TestWindow {
|
||||
|
||||
fn set_bounds(&self, _bounds: Size<i32, Logical>) {}
|
||||
|
||||
fn is_ignoring_opacity_window_rule(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn configure_intent(&self) -> ConfigureIntent {
|
||||
ConfigureIntent::CanSend
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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.)
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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.)
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -253,3 +253,14 @@ Or, in scripts:
|
||||
```shell
|
||||
niri msg action do-screen-transition --delay-ms 100
|
||||
```
|
||||
|
||||
#### `toggle-window-rule-opacity`
|
||||
|
||||
Toggle the opacity window rule of the focused window.
|
||||
This only has an effect if the window's opacity window rule is already set to semitransparent.
|
||||
|
||||
```kdl
|
||||
binds {
|
||||
Mod+O { toggle-window-rule-opacity; }
|
||||
}
|
||||
```
|
||||
|
@@ -492,6 +492,8 @@ This is applied on top of the window's own opacity, so semitransparent windows w
|
||||
|
||||
Opacity is applied to every surface of the window individually, so subsurfaces and pop-up menus will show window content behind them.
|
||||
|
||||
Opacity can be toggled on or off for a window using the [`toggle-window-rule-opacity`](./Configuration:-Key-Bindings.md) action.
|
||||
|
||||

|
||||
|
||||
Also, focus ring and border with background will show through semitransparent windows (see `prefer-no-csd` and the `draw-border-with-background` window rule below).
|
||||
|
Reference in New Issue
Block a user