diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-04-24 21:49:07 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-04-24 22:01:26 +0400 |
| commit | 3e598c565e6e8ad4c34e93aec9a49e60d51d730e (patch) | |
| tree | 95d3f12d04f3a416ba86915ebea01b7e0f66498e /src | |
| parent | e261b641ed62474676c90aaa4e734cdd1ecde703 (diff) | |
| download | niri-3e598c565e6e8ad4c34e93aec9a49e60d51d730e.tar.gz niri-3e598c565e6e8ad4c34e93aec9a49e60d51d730e.tar.bz2 niri-3e598c565e6e8ad4c34e93aec9a49e60d51d730e.zip | |
Implement border window rule
Diffstat (limited to 'src')
| -rw-r--r-- | src/handlers/xdg_shell.rs | 10 | ||||
| -rw-r--r-- | src/layout/mod.rs | 18 | ||||
| -rw-r--r-- | src/layout/tile.rs | 15 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 66 | ||||
| -rw-r--r-- | src/window/mod.rs | 16 |
5 files changed, 91 insertions, 34 deletions
diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index 36033da8..0b0a5a33 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -230,7 +230,7 @@ impl XdgShellHandler for State { // The required configure will be the initial configure. } - InitialConfigureState::Configured { output, .. } => { + InitialConfigureState::Configured { rules, output, .. } => { // Figure out the monitor following a similar logic to initial configure. // FIXME: deduplicate. let mon = requested_output @@ -269,7 +269,7 @@ impl XdgShellHandler for State { toplevel.with_pending_state(|state| { state.states.set(xdg_toplevel::State::Fullscreen); }); - ws.configure_new_window(&unmapped.window, None); + ws.configure_new_window(&unmapped.window, None, rules); } // We already sent the initial configure, so we need to reconfigure. @@ -302,10 +302,10 @@ impl XdgShellHandler for State { // The required configure will be the initial configure. } InitialConfigureState::Configured { + rules, width, is_full_width, output, - .. } => { // Figure out the monitor following a similar logic to initial configure. // FIXME: deduplicate. @@ -349,7 +349,7 @@ impl XdgShellHandler for State { } else { *width }; - ws.configure_new_window(&unmapped.window, configure_width); + ws.configure_new_window(&unmapped.window, configure_width, rules); } // We already sent the initial configure, so we need to reconfigure. @@ -580,7 +580,7 @@ impl State { } else { width }; - ws.configure_new_window(window, configure_width); + ws.configure_new_window(window, configure_width, &rules); } // If the user prefers no CSD, it's a reasonable assumption that they would prefer to get diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 4c570ef2..4889e9a7 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -463,8 +463,10 @@ impl<W: LayoutElement> Layout<W> { ) -> Option<&Output> { let mut width = width.unwrap_or_else(|| ColumnWidth::Fixed(window.size().w)); if let ColumnWidth::Fixed(w) = &mut width { - if !self.options.border.off { - *w += self.options.border.width as i32 * 2; + let rules = window.rules(); + let border_config = rules.border.resolve_against(self.options.border); + if !border_config.off { + *w += border_config.width as i32 * 2; } } @@ -519,8 +521,10 @@ impl<W: LayoutElement> Layout<W> { ) -> Option<&Output> { let mut width = width.unwrap_or_else(|| ColumnWidth::Fixed(window.size().w)); if let ColumnWidth::Fixed(w) = &mut width { - if !self.options.border.off { - *w += self.options.border.width as i32 * 2; + let rules = window.rules(); + let border_config = rules.border.resolve_against(self.options.border); + if !border_config.off { + *w += border_config.width as i32 * 2; } } @@ -555,8 +559,10 @@ impl<W: LayoutElement> Layout<W> { ) { let mut width = width.unwrap_or_else(|| ColumnWidth::Fixed(window.size().w)); if let ColumnWidth::Fixed(w) = &mut width { - if !self.options.border.off { - *w += self.options.border.width as i32 * 2; + let rules = window.rules(); + let border_config = rules.border.resolve_against(self.options.border); + if !border_config.off { + *w += border_config.width as i32 * 2; } } diff --git a/src/layout/tile.rs b/src/layout/tile.rs index ed6773da..4778db69 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -107,9 +107,12 @@ struct MoveAnimation { impl<W: LayoutElement> Tile<W> { pub fn new(window: W, options: Rc<Options>) -> Self { + let rules = window.rules(); + let border_config = rules.border.resolve_against(options.border); + Self { window, - border: FocusRing::new(options.border.into()), + border: FocusRing::new(border_config.into()), focus_ring: FocusRing::new(options.focus_ring), is_fullscreen: false, // FIXME: up-to-date fullscreen right away, but we need size. fullscreen_backdrop: SolidColorBuffer::new((0, 0), [0., 0., 0., 1.]), @@ -123,7 +126,11 @@ impl<W: LayoutElement> Tile<W> { } pub fn update_config(&mut self, options: Rc<Options>) { - self.border.update_config(options.border.into()); + let rules = self.window.rules(); + + let border_config = rules.border.resolve_against(self.options.border); + self.border.update_config(border_config.into()); + self.focus_ring.update_config(options.focus_ring); self.options = options; } @@ -164,6 +171,10 @@ impl<W: LayoutElement> Tile<W> { self.resize_animation = None; } } + + let rules = self.window.rules(); + let border_config = rules.border.resolve_against(self.options.border); + self.border.update_config(border_config.into()); } pub fn advance_animations(&mut self, current_time: Duration, is_active: bool) { diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index b6b38285..fd5662b8 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -23,6 +23,7 @@ use crate::render_helpers::RenderTarget; use crate::swipe_tracker::SwipeTracker; use crate::utils::id::IdCounter; use crate::utils::output_size; +use crate::window::ResolvedWindowRules; /// Amount of touchpad movement to scroll the view for the width of one working area. const VIEW_GESTURE_WORKING_AREA_MOVEMENT: f64 = 1200.; @@ -406,16 +407,9 @@ impl<W: LayoutElement> Workspace<W> { } } - fn toplevel_bounds(&self) -> Size<i32, Logical> { - let mut border = 0; - if !self.options.border.off { - border = self.options.border.width as i32 * 2; - } - - Size::from(( - max(self.working_area.size.w - self.options.gaps * 2 - border, 1), - max(self.working_area.size.h - self.options.gaps * 2 - border, 1), - )) + fn toplevel_bounds(&self, rules: &ResolvedWindowRules) -> Size<i32, Logical> { + let border_config = rules.border.resolve_against(self.options.border); + compute_toplevel_bounds(border_config, self.working_area.size, self.options.gaps) } pub fn resolve_default_width( @@ -429,14 +423,20 @@ impl<W: LayoutElement> Workspace<W> { } } - pub fn new_window_size(&self, width: Option<ColumnWidth>) -> Size<i32, Logical> { + pub fn new_window_size( + &self, + width: Option<ColumnWidth>, + rules: &ResolvedWindowRules, + ) -> Size<i32, Logical> { + let border = rules.border.resolve_against(self.options.border); + let width = if let Some(width) = width { let is_fixed = matches!(width, ColumnWidth::Fixed(_)); let mut width = width.resolve(&self.options, self.working_area.size.w); - if !is_fixed && !self.options.border.off { - width -= self.options.border.width as i32 * 2; + if !is_fixed && !border.off { + width -= border.width as i32 * 2; } max(1, width) @@ -445,14 +445,19 @@ impl<W: LayoutElement> Workspace<W> { }; let mut height = self.working_area.size.h - self.options.gaps * 2; - if !self.options.border.off { - height -= self.options.border.width as i32 * 2; + if !border.off { + height -= border.width as i32 * 2; } Size::from((width, max(height, 1))) } - pub fn configure_new_window(&self, window: &Window, width: Option<ColumnWidth>) { + pub fn configure_new_window( + &self, + window: &Window, + width: Option<ColumnWidth>, + rules: &ResolvedWindowRules, + ) { if let Some(output) = self.output.as_ref() { let scale = output.current_scale().integer_scale(); let transform = output.current_transform(); @@ -468,10 +473,10 @@ impl<W: LayoutElement> Workspace<W> { if state.states.contains(xdg_toplevel::State::Fullscreen) { state.size = Some(self.view_size); } else { - state.size = Some(self.new_window_size(width)); + state.size = Some(self.new_window_size(width, rules)); } - state.bounds = Some(self.toplevel_bounds()); + state.bounds = Some(self.toplevel_bounds(rules)); }); } @@ -2134,8 +2139,6 @@ impl<W: LayoutElement> Workspace<W> { } pub fn refresh(&mut self, is_active: bool) { - let bounds = self.toplevel_bounds(); - for (col_idx, col) in self.columns.iter_mut().enumerate() { for (tile_idx, tile) in col.tiles.iter_mut().enumerate() { let win = tile.window_mut(); @@ -2144,7 +2147,14 @@ impl<W: LayoutElement> Workspace<W> { && col.active_tile_idx == tile_idx; win.set_activated(active); + let border_config = win.rules().border.resolve_against(self.options.border); + let bounds = compute_toplevel_bounds( + border_config, + self.working_area.size, + self.options.gaps, + ); win.set_bounds(bounds); + win.send_pending_configure(); win.refresh(); } @@ -2824,3 +2834,19 @@ pub fn compute_working_area(output: &Output, struts: Struts) -> Rectangle<i32, L working_area } + +fn compute_toplevel_bounds( + border_config: niri_config::Border, + working_area_size: Size<i32, Logical>, + gaps: i32, +) -> Size<i32, Logical> { + let mut border = 0; + if !border_config.off { + border = border_config.width as i32 * 2; + } + + Size::from(( + max(working_area_size.w - gaps * 2 - border, 1), + max(working_area_size.h - gaps * 2 - border, 1), + )) +} diff --git a/src/window/mod.rs b/src/window/mod.rs index 3c46e9e5..a793cedb 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -1,4 +1,4 @@ -use niri_config::{BlockOutFrom, Match, WindowRule}; +use niri_config::{BlockOutFrom, BorderRule, Match, WindowRule}; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; use smithay::wayland::compositor::with_states; use smithay::wayland::shell::xdg::{ @@ -48,6 +48,9 @@ pub struct ResolvedWindowRules { /// Extra bound on the maximum window height. pub max_height: Option<u16>, + /// Window border overrides. + pub border: BorderRule, + /// Whether or not to draw the border with a solid background. /// /// `None` means using the SSD heuristic. @@ -87,6 +90,15 @@ impl ResolvedWindowRules { min_height: None, max_width: None, max_height: None, + border: BorderRule { + off: false, + on: false, + width: None, + active_color: None, + inactive_color: None, + active_gradient: None, + inactive_gradient: None, + }, draw_border_with_background: None, opacity: None, block_out_from: None, @@ -158,6 +170,8 @@ impl ResolvedWindowRules { resolved.max_height = Some(x); } + resolved.border.merge_with(&rule.border); + if let Some(x) = rule.draw_border_with_background { resolved.draw_border_with_background = Some(x); } |
