Implement draw-border-with-background window rule

This commit is contained in:
Ivan Molodetskikh 2024-03-19 18:22:25 +04:00
parent c61361de3c
commit db49deb7fd
8 changed files with 79 additions and 7 deletions

View File

@ -693,6 +693,9 @@ pub struct WindowRule {
pub max_width: Option<u16>,
#[knuffel(child, unwrap(argument))]
pub max_height: Option<u16>,
#[knuffel(child, unwrap(argument))]
pub draw_border_with_background: Option<bool>,
}
#[derive(knuffel::Decode, Debug, Default, Clone)]

View File

@ -4,6 +4,7 @@ use std::rc::Rc;
use niri::layout::{LayoutElement, LayoutElementRenderElement};
use niri::render_helpers::renderer::NiriRenderer;
use niri::window::ResolvedWindowRules;
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
use smithay::backend::renderer::element::{Id, Kind};
use smithay::output::Output;
@ -217,4 +218,9 @@ impl LayoutElement for TestWindow {
}
fn refresh(&self) {}
fn rules(&self) -> &ResolvedWindowRules {
static EMPTY: ResolvedWindowRules = ResolvedWindowRules::empty();
&EMPTY
}
}

View File

@ -123,6 +123,9 @@ layout {
// If you don't like that, you should uncomment `prefer-no-csd` below.
// Niri will draw focus ring and border *around* windows that agree to omit their
// client-side decorations.
//
// Alternatively, you can override it with a window rule called
// `draw-border-with-background`.
// You can change how the focus ring looks.
focus-ring {
@ -393,6 +396,13 @@ animations {
// if it is equal to min-height. Either set this equal to min-height,
// or change the window height manually for this to apply.
max-height 300
// Override whether the border and the focus ring draw with a background.
// Set this to `true` to draw them as solid colored rectangles even for
// windows which agreed to omit their client-side decorations.
// Set this to `false` to draw them as borders around the window even for
// windows which use client-side decorations.
draw-border-with-background false
}
// Here's a useful example. Work around WezTerm's initial configure bug

View File

@ -123,7 +123,7 @@ impl CompositorHandler for State {
(rules, width, is_full_width, output)
} else {
error!("window map must happen after initial configure");
(ResolvedWindowRules::default(), None, false, None)
(ResolvedWindowRules::empty(), None, false, None)
};
let parent = window

View File

@ -49,6 +49,7 @@ use self::workspace::{compute_working_area, Column, ColumnWidth, OutputId, Works
use crate::niri_render_elements;
use crate::render_helpers::renderer::NiriRenderer;
use crate::utils::output_size;
use crate::window::ResolvedWindowRules;
pub mod focus_ring;
pub mod monitor;
@ -121,6 +122,8 @@ pub trait LayoutElement {
/// This *will* switch immediately after a [`LayoutElement::request_fullscreen()`] call.
fn is_pending_fullscreen(&self) -> bool;
fn rules(&self) -> &ResolvedWindowRules;
/// Runs periodic clean-up tasks.
fn refresh(&self);
}
@ -1905,6 +1908,11 @@ mod tests {
}
fn refresh(&self) {}
fn rules(&self) -> &ResolvedWindowRules {
static EMPTY: ResolvedWindowRules = ResolvedWindowRules::empty();
&EMPTY
}
}
fn arbitrary_bbox() -> impl Strategy<Value = Rectangle<i32, Logical>> {

View File

@ -85,11 +85,22 @@ impl<W: LayoutElement> Tile<W> {
}
pub fn advance_animations(&mut self, current_time: Duration, is_active: bool) {
let draw_border_with_background = self
.window
.rules()
.draw_border_with_background
.unwrap_or_else(|| !self.window.has_ssd());
self.border
.update(self.window.size(), self.window.has_ssd());
.update(self.window.size(), !draw_border_with_background);
self.border.set_active(is_active);
self.focus_ring.update(self.tile_size(), self.has_ssd());
let draw_focus_ring_with_background = if self.effective_border_width().is_some() {
false
} else {
draw_border_with_background
};
self.focus_ring
.update(self.tile_size(), !draw_focus_ring_with_background);
self.focus_ring.set_active(is_active);
match &mut self.open_animation {
@ -295,8 +306,15 @@ impl<W: LayoutElement> Tile<W> {
size
}
pub fn has_ssd(&self) -> bool {
self.effective_border_width().is_some() || self.window.has_ssd()
pub fn draw_border_with_background(&self) -> bool {
if self.effective_border_width().is_some() {
return false;
}
self.window
.rules()
.draw_border_with_background
.unwrap_or_else(|| !self.window.has_ssd())
}
fn render_inner<R: NiriRenderer>(

View File

@ -184,4 +184,8 @@ impl LayoutElement for Mapped {
fn refresh(&self) {
self.window.refresh();
}
fn rules(&self) -> &ResolvedWindowRules {
&self.rules
}
}

View File

@ -13,7 +13,7 @@ pub mod unmapped;
pub use unmapped::{InitialConfigureState, Unmapped};
/// Rules fully resolved for a window.
#[derive(Debug, Default, PartialEq)]
#[derive(Debug, PartialEq)]
pub struct ResolvedWindowRules {
/// Default width for this window.
///
@ -39,13 +39,32 @@ pub struct ResolvedWindowRules {
pub max_width: Option<u16>,
/// Extra bound on the maximum window height.
pub max_height: Option<u16>,
/// Whether or not to draw the border with a solid background.
///
/// `None` means using the SSD heuristic.
pub draw_border_with_background: Option<bool>,
}
impl ResolvedWindowRules {
pub const fn empty() -> Self {
Self {
default_width: None,
open_on_output: None,
open_maximized: None,
open_fullscreen: None,
min_width: None,
min_height: None,
max_width: None,
max_height: None,
draw_border_with_background: None,
}
}
pub fn compute(rules: &[WindowRule], toplevel: &ToplevelSurface) -> Self {
let _span = tracy_client::span!("ResolvedWindowRules::compute");
let mut resolved = ResolvedWindowRules::default();
let mut resolved = ResolvedWindowRules::empty();
with_states(toplevel.wl_surface(), |states| {
let role = states
@ -100,6 +119,10 @@ impl ResolvedWindowRules {
if let Some(x) = rule.max_height {
resolved.max_height = Some(x);
}
if let Some(x) = rule.draw_border_with_background {
resolved.draw_border_with_background = Some(x);
}
}
resolved.open_on_output = open_on_output.map(|x| x.to_owned());