layout: Store Layout directly in Options

This commit is contained in:
Ivan Molodetskikh
2025-09-20 12:57:42 +03:00
parent 1fa9dd32ed
commit 4c524b4719
11 changed files with 279 additions and 274 deletions

View File

@@ -52,20 +52,23 @@ impl Layout {
});
let options = Options {
focus_ring: niri_config::FocusRing {
off: true,
layout: niri_config::Layout {
focus_ring: niri_config::FocusRing {
off: true,
..Default::default()
},
border: niri_config::Border {
off: false,
width: 4.,
active_color: Color::from_rgba8_unpremul(255, 163, 72, 255),
inactive_color: Color::from_rgba8_unpremul(50, 50, 50, 255),
urgent_color: Color::from_rgba8_unpremul(155, 0, 0, 255),
active_gradient: None,
inactive_gradient: None,
urgent_gradient: None,
},
..Default::default()
},
border: niri_config::Border {
off: false,
width: 4.,
active_color: Color::from_rgba8_unpremul(255, 163, 72, 255),
inactive_color: Color::from_rgba8_unpremul(50, 50, 50, 255),
urgent_color: Color::from_rgba8_unpremul(155, 0, 0, 255),
active_gradient: None,
inactive_gradient: None,
urgent_gradient: None,
},
..Default::default()
};
let mut layout = niri::layout::Layout::with_options(clock.clone(), options);

View File

@@ -58,14 +58,17 @@ impl Tile {
let Args { size, clock } = args;
let options = Options {
focus_ring: niri_config::FocusRing {
off: true,
..Default::default()
},
border: niri_config::Border {
off: false,
width: 32.,
active_color: Color::from_rgba8_unpremul(255, 163, 72, 255),
layout: niri_config::Layout {
focus_ring: niri_config::FocusRing {
off: true,
..Default::default()
},
border: niri_config::Border {
off: false,
width: 32.,
active_color: Color::from_rgba8_unpremul(255, 163, 72, 255),
..Default::default()
},
..Default::default()
},
..Default::default()

View File

@@ -340,7 +340,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
}
pub fn new_window_toplevel_bounds(&self, rules: &ResolvedWindowRules) -> Size<i32, Logical> {
let border_config = self.options.border.merged_with(&rules.border);
let border_config = self.options.layout.border.merged_with(&rules.border);
compute_toplevel_bounds(border_config, self.working_area.size)
}
@@ -633,7 +633,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
let available_size = self.working_area.size.w;
let len = self.options.preset_column_widths.len();
let len = self.options.layout.preset_column_widths.len();
let tile = &mut self.tiles[idx];
let preset_idx = if let Some(idx) = tile.floating_preset_width_idx {
(idx + if forwards { 1 } else { len - 1 }) % len
@@ -643,6 +643,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
let mut it = self
.options
.layout
.preset_column_widths
.iter()
.map(|preset| resolve_preset_size(*preset, available_size));
@@ -668,7 +669,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
}
};
let preset = self.options.preset_column_widths[preset_idx];
let preset = self.options.layout.preset_column_widths[preset_idx];
self.set_window_width(Some(&id), SizeChange::from(preset), true);
self.tiles[idx].floating_preset_width_idx = Some(preset_idx);
@@ -693,7 +694,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
let available_size = self.working_area.size.h;
let len = self.options.preset_window_heights.len();
let len = self.options.layout.preset_window_heights.len();
let tile = &mut self.tiles[idx];
let preset_idx = if let Some(idx) = tile.floating_preset_height_idx {
(idx + if forwards { 1 } else { len - 1 }) % len
@@ -703,6 +704,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
let mut it = self
.options
.layout
.preset_window_heights
.iter()
.map(|preset| resolve_preset_size(*preset, available_size));
@@ -728,7 +730,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
}
};
let preset = self.options.preset_window_heights[preset_idx];
let preset = self.options.layout.preset_window_heights[preset_idx];
self.set_window_height(Some(&id), SizeChange::from(preset), true);
let tile = &mut self.tiles[idx];
@@ -1156,7 +1158,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
.map(|resize| resize.data);
win.set_interactive_resize(resize_data);
let border_config = self.options.border.merged_with(&win.rules().border);
let border_config = self.options.layout.border.merged_with(&win.rules().border);
let bounds = compute_toplevel_bounds(border_config, self.working_area.size);
win.set_bounds(bounds);
@@ -1220,7 +1222,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
height: Option<PresetSize>,
rules: &ResolvedWindowRules,
) -> Size<i32, Logical> {
let border = self.options.border.merged_with(&rules.border);
let border = self.options.layout.border.merged_with(&rules.border);
let resolve = |size: Option<PresetSize>, working_area_size: f64| {
if let Some(size) = size {
@@ -1317,10 +1319,10 @@ impl<W: LayoutElement> FloatingSpace<W> {
tile.verify_invariants();
if let Some(idx) = tile.floating_preset_width_idx {
assert!(idx < self.options.preset_column_widths.len());
assert!(idx < self.options.layout.preset_column_widths.len());
}
if let Some(idx) = tile.floating_preset_height_idx {
assert!(idx < self.options.preset_window_heights.len());
assert!(idx < self.options.layout.preset_window_heights.len());
}
assert!(

View File

@@ -40,8 +40,7 @@ use std::time::Duration;
use monitor::{InsertHint, InsertPosition, InsertWorkspace, MonitorAddWindowTarget};
use niri_config::utils::MergeWith as _;
use niri_config::{
CenterFocusedColumn, Config, CornerRadius, PresetSize, Struts, Workspace as WorkspaceConfig,
WorkspaceReference,
Config, CornerRadius, PresetSize, Workspace as WorkspaceConfig, WorkspaceReference,
};
use niri_ipc::{ColumnDisplay, PositionChange, SizeChange, WindowLayout};
use scrolling::{Column, ColumnWidth};
@@ -334,27 +333,9 @@ enum MonitorSet<W: LayoutElement> {
},
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Options {
/// Padding around windows in logical pixels.
pub gaps: f64,
/// Extra padding around the working area in logical pixels.
pub struts: Struts,
pub focus_ring: niri_config::FocusRing,
pub border: niri_config::Border,
pub shadow: niri_config::Shadow,
pub tab_indicator: niri_config::TabIndicator,
pub insert_hint: niri_config::InsertHint,
pub center_focused_column: CenterFocusedColumn,
pub always_center_single_column: bool,
pub empty_workspace_above_first: bool,
pub default_column_display: ColumnDisplay,
/// Column or window widths that `toggle_width()` switches between.
pub preset_column_widths: Vec<PresetSize>,
/// Initial width for new columns.
pub default_column_width: Option<PresetSize>,
/// Window height that `toggle_window_height()` switches between.
pub preset_window_heights: Vec<PresetSize>,
pub layout: niri_config::Layout,
pub animations: niri_config::Animations,
pub gestures: niri_config::Gestures,
pub overview: niri_config::Overview,
@@ -364,41 +345,6 @@ pub struct Options {
pub deactivate_unfocused_windows: bool,
}
impl Default for Options {
fn default() -> Self {
Self {
gaps: 16.,
struts: Default::default(),
focus_ring: Default::default(),
border: Default::default(),
shadow: Default::default(),
tab_indicator: Default::default(),
insert_hint: Default::default(),
center_focused_column: Default::default(),
always_center_single_column: false,
empty_workspace_above_first: false,
default_column_display: ColumnDisplay::Normal,
preset_column_widths: vec![
PresetSize::Proportion(1. / 3.),
PresetSize::Proportion(0.5),
PresetSize::Proportion(2. / 3.),
],
default_column_width: None,
animations: Default::default(),
gestures: Default::default(),
overview: Default::default(),
disable_resize_throttling: false,
disable_transactions: false,
preset_window_heights: vec![
PresetSize::Proportion(1. / 3.),
PresetSize::Proportion(0.5),
PresetSize::Proportion(2. / 3.),
],
deactivate_unfocused_windows: false,
}
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
enum InteractiveMoveState<W: LayoutElement> {
@@ -620,49 +566,23 @@ impl HitType {
impl Options {
fn from_config(config: &Config) -> Self {
let layout = config.resolve_layout();
let preset_column_widths = if layout.preset_column_widths.is_empty() {
Options::default().preset_column_widths
} else {
layout.preset_column_widths.clone()
};
let preset_window_heights = if layout.preset_window_heights.is_empty() {
Options::default().preset_window_heights
} else {
layout.preset_window_heights.clone()
};
Self {
gaps: layout.gaps,
struts: layout.struts,
focus_ring: layout.focus_ring,
border: layout.border,
shadow: layout.shadow,
tab_indicator: layout.tab_indicator,
insert_hint: layout.insert_hint,
center_focused_column: layout.center_focused_column,
always_center_single_column: layout.always_center_single_column,
empty_workspace_above_first: layout.empty_workspace_above_first,
default_column_display: layout.default_column_display,
preset_column_widths,
default_column_width: layout.default_column_width,
layout: config.resolve_layout(),
animations: config.animations.clone(),
gestures: config.gestures,
overview: config.overview,
disable_resize_throttling: config.debug.disable_resize_throttling,
disable_transactions: config.debug.disable_transactions,
deactivate_unfocused_windows: config.debug.deactivate_unfocused_windows,
preset_window_heights,
}
}
fn adjusted_for_scale(mut self, scale: f64) -> Self {
let round = |logical: f64| round_logical_in_physical_max1(scale, logical);
self.gaps = round(self.gaps);
self.focus_ring.width = round(self.focus_ring.width);
self.border.width = round(self.border.width);
self.layout.gaps = round(self.layout.gaps);
self.layout.focus_ring.width = round(self.layout.focus_ring.width);
self.layout.border.width = round(self.layout.border.width);
self
}
@@ -775,7 +695,7 @@ impl<W: LayoutElement> Layout<W> {
// workspaces set up across multiple monitors. Without this check, the
// first monitor to connect can end up with the first empty workspace
// focused instead of the first named workspace.
&& !(self.options.empty_workspace_above_first
&& !(self.options.layout.empty_workspace_above_first
&& primary.active_workspace_idx == 1)
{
primary.active_workspace_idx =
@@ -790,7 +710,7 @@ impl<W: LayoutElement> Layout<W> {
// takes care of this.
if stopped_primary_ws_switch
|| (primary.options.empty_workspace_above_first
|| (primary.options.layout.empty_workspace_above_first
&& primary.workspaces.len() == 2)
{
primary.clean_up_workspaces();
@@ -810,7 +730,7 @@ impl<W: LayoutElement> Layout<W> {
self.options.clone(),
));
if self.options.empty_workspace_above_first && workspaces.len() > 1 {
if self.options.layout.empty_workspace_above_first && workspaces.len() > 1 {
workspaces.insert(
0,
Workspace::new(output.clone(), self.clock.clone(), self.options.clone()),
@@ -844,7 +764,7 @@ impl<W: LayoutElement> Layout<W> {
));
let mut active_workspace_idx = 0;
if self.options.empty_workspace_above_first && workspaces.len() > 1 {
if self.options.layout.empty_workspace_above_first && workspaces.len() > 1 {
workspaces.insert(
0,
Workspace::new(output.clone(), self.clock.clone(), self.options.clone()),
@@ -944,7 +864,7 @@ impl<W: LayoutElement> Layout<W> {
// If empty_workspace_above_first is set and the first workspace is now no
// longer empty, add a new empty workspace on top.
if primary.options.empty_workspace_above_first
if primary.options.layout.empty_workspace_above_first
&& primary.workspaces[0].has_windows_or_name()
{
primary.add_workspace_top();
@@ -1242,7 +1162,7 @@ impl<W: LayoutElement> Layout<W> {
// Special case handling when empty_workspace_above_first is set and all
// workspaces are empty.
if mon.options.empty_workspace_above_first
if mon.options.layout.empty_workspace_above_first
&& mon.workspaces.len() == 2
&& mon.workspace_switch.is_none()
{
@@ -2637,7 +2557,7 @@ impl<W: LayoutElement> Layout<W> {
!monitor.workspaces.last().unwrap().has_windows(),
"monitor must have an empty workspace in the end"
);
if monitor.options.empty_workspace_above_first {
if monitor.options.layout.empty_workspace_above_first {
assert!(
!monitor.workspaces.first().unwrap().has_windows(),
"first workspace must be empty when empty_workspace_above_first is set"
@@ -2648,14 +2568,14 @@ impl<W: LayoutElement> Layout<W> {
monitor.workspaces.last().unwrap().name.is_none(),
"monitor must have an unnamed workspace in the end"
);
if monitor.options.empty_workspace_above_first {
if monitor.options.layout.empty_workspace_above_first {
assert!(
monitor.workspaces.first().unwrap().name.is_none(),
"first workspace must be unnamed when empty_workspace_above_first is set"
)
}
if monitor.options.empty_workspace_above_first {
if monitor.options.layout.empty_workspace_above_first {
assert!(
monitor.workspaces.len() != 2,
"if empty_workspace_above_first is set there must be just 1 or 3+ workspaces"
@@ -2665,7 +2585,7 @@ impl<W: LayoutElement> Layout<W> {
// If there's no workspace switch in progress, there can't be any non-last non-active
// empty workspaces. If empty_workspace_above_first is set then the first workspace
// will be empty too.
let pre_skip = if monitor.options.empty_workspace_above_first {
let pre_skip = if monitor.options.layout.empty_workspace_above_first {
1
} else {
0
@@ -3107,7 +3027,7 @@ impl<W: LayoutElement> Layout<W> {
let mon = &mut monitors[mon_idx];
let mut insert_idx = 0;
if mon.options.empty_workspace_above_first {
if mon.options.layout.empty_workspace_above_first {
// need to insert new empty workspace on top
mon.add_workspace_top();
insert_idx += 1;
@@ -3622,7 +3542,7 @@ impl<W: LayoutElement> Layout<W> {
// Insert a new empty workspace.
current.add_workspace_bottom();
}
if current.options.empty_workspace_above_first && current.active_workspace_idx == 0 {
if current.options.layout.empty_workspace_above_first && current.active_workspace_idx == 0 {
current.add_workspace_top();
}
@@ -3642,7 +3562,7 @@ impl<W: LayoutElement> Layout<W> {
target.previous_workspace_id = Some(target.workspaces[target.active_workspace_idx].id());
if target.options.empty_workspace_above_first && target.workspaces.len() == 1 {
if target.options.layout.empty_workspace_above_first && target.workspaces.len() == 1 {
// Insert a new empty workspace on top to prepare for insertion of new workspace.
target.add_workspace_top();
}
@@ -3711,7 +3631,7 @@ impl<W: LayoutElement> Layout<W> {
let mut ws = current.workspaces.remove(old_idx);
if current.options.empty_workspace_above_first && old_idx == 0 {
if current.options.layout.empty_workspace_above_first && old_idx == 0 {
current.add_workspace_top();
}
@@ -3728,7 +3648,7 @@ impl<W: LayoutElement> Layout<W> {
target.previous_workspace_id = Some(target.workspaces[target.active_workspace_idx].id());
if target.options.empty_workspace_above_first && target.workspaces.len() == 1 {
if target.options.layout.empty_workspace_above_first && target.workspaces.len() == 1 {
// Insert a new empty workspace on top to prepare for insertion of new workspace.
target.add_workspace_top();
}
@@ -4480,7 +4400,7 @@ impl<W: LayoutElement> Layout<W> {
.position(|ws| ws.id() == ws_id)
.unwrap(),
InsertWorkspace::NewAt(ws_idx) => {
if self.options.empty_workspace_above_first && ws_idx == 0 {
if self.options.layout.empty_workspace_above_first && ws_idx == 0 {
// Reuse the top empty workspace.
0
} else if mon.workspaces.len() - 1 <= ws_idx {
@@ -4813,7 +4733,7 @@ impl<W: LayoutElement> Layout<W> {
} = &mut self.monitor_set
{
let monitor = &mut monitors[*active_monitor_idx];
if self.options.empty_workspace_above_first
if self.options.layout.empty_workspace_above_first
&& monitor
.workspaces
.first()
@@ -5242,7 +5162,7 @@ impl<W: LayoutElement> Layout<W> {
// Add border width since ColumnWidth includes borders.
let rules = window.rules();
let border = self.options.border.merged_with(&rules.border);
let border = self.options.layout.border.merged_with(&rules.border);
if !border.off {
fixed += border.width * 2.;
}

View File

@@ -293,7 +293,7 @@ impl<W: LayoutElement> Monitor<W> {
active_workspace_idx: 0,
previous_workspace_id: None,
insert_hint: None,
insert_hint_element: InsertHintElement::new(options.insert_hint),
insert_hint_element: InsertHintElement::new(options.layout.insert_hint),
insert_hint_render_loc: None,
overview_open: false,
overview_progress: None,
@@ -463,7 +463,7 @@ impl<W: LayoutElement> Monitor<W> {
if workspace_idx == self.workspaces.len() - 1 {
self.add_workspace_bottom();
}
if self.options.empty_workspace_above_first && workspace_idx == 0 {
if self.options.layout.empty_workspace_above_first && workspace_idx == 0 {
self.add_workspace_top();
workspace_idx += 1;
}
@@ -522,7 +522,7 @@ impl<W: LayoutElement> Monitor<W> {
self.add_workspace_bottom();
}
if self.options.empty_workspace_above_first && workspace_idx == 0 {
if self.options.layout.empty_workspace_above_first && workspace_idx == 0 {
self.add_workspace_top();
workspace_idx += 1;
}
@@ -562,7 +562,7 @@ impl<W: LayoutElement> Monitor<W> {
pub fn clean_up_workspaces(&mut self) {
assert!(self.workspace_switch.is_none());
let range_start = if self.options.empty_workspace_above_first {
let range_start = if self.options.layout.empty_workspace_above_first {
1
} else {
0
@@ -582,7 +582,7 @@ impl<W: LayoutElement> Monitor<W> {
// Special case handling when empty_workspace_above_first is set and all workspaces
// are empty.
if self.options.empty_workspace_above_first && self.workspaces.len() == 2 {
if self.options.layout.empty_workspace_above_first && self.workspaces.len() == 2 {
assert!(!self.workspaces[0].has_windows_or_name());
assert!(!self.workspaces[1].has_windows_or_name());
self.workspaces.remove(1);
@@ -1023,10 +1023,11 @@ impl<W: LayoutElement> Monitor<W> {
}
pub fn update_config(&mut self, options: Rc<Options>) {
if self.options.empty_workspace_above_first != options.empty_workspace_above_first
if self.options.layout.empty_workspace_above_first
!= options.layout.empty_workspace_above_first
&& self.workspaces.len() > 1
{
if options.empty_workspace_above_first {
if options.layout.empty_workspace_above_first {
self.add_workspace_top();
} else if self.workspace_switch.is_none() && self.active_workspace_idx != 0 {
self.workspaces.remove(0);
@@ -1038,7 +1039,8 @@ impl<W: LayoutElement> Monitor<W> {
ws.update_config(options.clone());
}
self.insert_hint_element.update_config(options.insert_hint);
self.insert_hint_element
.update_config(options.layout.insert_hint);
self.options = options;
}
@@ -1074,7 +1076,7 @@ impl<W: LayoutElement> Monitor<W> {
self.add_workspace_bottom();
}
if self.options.empty_workspace_above_first && self.active_workspace_idx == 0 {
if self.options.layout.empty_workspace_above_first && self.active_workspace_idx == 0 {
self.add_workspace_top();
new_idx += 1;
}
@@ -1100,7 +1102,7 @@ impl<W: LayoutElement> Monitor<W> {
self.add_workspace_bottom();
}
if self.options.empty_workspace_above_first && new_idx == 0 {
if self.options.layout.empty_workspace_above_first && new_idx == 0 {
self.add_workspace_top();
new_idx += 1;
}
@@ -1132,7 +1134,7 @@ impl<W: LayoutElement> Monitor<W> {
self.add_workspace_bottom();
}
if self.options.empty_workspace_above_first && old_idx == 0 {
if self.options.layout.empty_workspace_above_first && old_idx == 0 {
self.add_workspace_top();
new_idx += 1;
}
@@ -1142,7 +1144,7 @@ impl<W: LayoutElement> Monitor<W> {
self.add_workspace_bottom();
}
if self.options.empty_workspace_above_first && new_idx == 0 {
if self.options.layout.empty_workspace_above_first && new_idx == 0 {
self.add_workspace_top();
new_idx += 1;
}
@@ -1464,7 +1466,7 @@ impl<W: LayoutElement> Monitor<W> {
) -> impl Iterator<Item = MonitorRenderElement<R>> {
let mut rv = None;
if !self.options.insert_hint.off {
if !self.options.layout.insert_hint.off {
if let Some(render_loc) = self.insert_hint_render_loc {
if let InsertWorkspace::NewAt(_) = render_loc.workspace {
let iter = self
@@ -1525,7 +1527,7 @@ impl<W: LayoutElement> Monitor<W> {
// Draw the insert hint.
let mut insert_hint = None;
if !self.options.insert_hint.off {
if !self.options.layout.insert_hint.off {
if let Some(render_loc) = self.insert_hint_render_loc {
if let InsertWorkspace::Existing(workspace_id) = render_loc.workspace {
insert_hint = Some((

View File

@@ -276,7 +276,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
clock: Clock,
options: Rc<Options>,
) -> Self {
let working_area = compute_working_area(parent_area, scale, options.struts);
let working_area = compute_working_area(parent_area, scale, options.layout.struts);
Self {
columns: Vec::new(),
@@ -303,7 +303,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
scale: f64,
options: Rc<Options>,
) {
let working_area = compute_working_area(parent_area, scale, options.struts);
let working_area = compute_working_area(parent_area, scale, options.layout.struts);
for (column, data) in zip(&mut self.columns, &mut self.data) {
column.update_config(view_size, working_area, scale, options.clone());
@@ -444,14 +444,14 @@ impl<W: LayoutElement> ScrollingSpace<W> {
}
pub fn new_window_toplevel_bounds(&self, rules: &ResolvedWindowRules) -> Size<i32, Logical> {
let border_config = self.options.border.merged_with(&rules.border);
let border_config = self.options.layout.border.merged_with(&rules.border);
let display_mode = rules
.default_column_display
.unwrap_or(self.options.default_column_display);
.unwrap_or(self.options.layout.default_column_display);
let will_tab = display_mode == ColumnDisplay::Tabbed;
let extra_size = if will_tab {
TabIndicator::new(self.options.tab_indicator).extra_size(1, self.scale)
TabIndicator::new(self.options.layout.tab_indicator).extra_size(1, self.scale)
} else {
Size::from((0., 0.))
};
@@ -460,7 +460,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
border_config,
self.working_area.size,
extra_size,
self.options.gaps,
self.options.layout.gaps,
)
}
@@ -470,14 +470,14 @@ impl<W: LayoutElement> ScrollingSpace<W> {
height: Option<PresetSize>,
rules: &ResolvedWindowRules,
) -> Size<i32, Logical> {
let border = self.options.border.merged_with(&rules.border);
let border = self.options.layout.border.merged_with(&rules.border);
let display_mode = rules
.default_column_display
.unwrap_or(self.options.default_column_display);
.unwrap_or(self.options.layout.default_column_display);
let will_tab = display_mode == ColumnDisplay::Tabbed;
let extra = if will_tab {
TabIndicator::new(self.options.tab_indicator).extra_size(1, self.scale)
TabIndicator::new(self.options.layout.tab_indicator).extra_size(1, self.scale)
} else {
Size::from((0., 0.))
};
@@ -500,7 +500,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
0
};
let mut full_height = self.working_area.size.h - self.options.gaps * 2.;
let mut full_height = self.working_area.size.h - self.options.layout.gaps * 2.;
if !border.off {
full_height -= border.width * 2.;
}
@@ -524,8 +524,8 @@ impl<W: LayoutElement> ScrollingSpace<W> {
}
pub fn is_centering_focused_column(&self) -> bool {
self.options.center_focused_column == CenterFocusedColumn::Always
|| (self.options.always_center_single_column && self.columns.len() <= 1)
self.options.layout.center_focused_column == CenterFocusedColumn::Always
|| (self.options.layout.always_center_single_column && self.columns.len() <= 1)
}
fn compute_new_view_offset_fit(
@@ -546,7 +546,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
self.working_area.size.w,
col_x,
width,
self.options.gaps,
self.options.layout.gaps,
);
// Non-fullscreen windows are always offset at least by the working area position.
@@ -606,7 +606,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
return self.compute_new_view_offset_for_column_centered(target_x, idx);
}
match self.options.center_focused_column {
match self.options.layout.center_focused_column {
CenterFocusedColumn::Always => {
self.compute_new_view_offset_for_column_centered(target_x, idx)
}
@@ -639,7 +639,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
} else {
// Source is right from target.
source_col_x - target_col_x + source_col_width
} + self.options.gaps * 2.;
} + self.options.layout.gaps * 2.;
// If it fits together, do a normal animation, otherwise center the new column.
if total_width <= self.working_area.size.w {
@@ -783,8 +783,8 @@ impl<W: LayoutElement> ScrollingSpace<W> {
let x = pos.x + self.view_pos();
// Aim for the center of the gap.
let x = x + self.options.gaps / 2.;
let y = pos.y + self.options.gaps / 2.;
let x = x + self.options.layout.gaps / 2.;
let y = pos.y + self.options.layout.gaps / 2.;
// Insert position is before the first column.
if x < 0. {
@@ -2224,7 +2224,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
let mut leftmost_col_x = None;
let mut active_col_x = None;
let gap = self.options.gaps;
let gap = self.options.layout.gaps;
let col_xs = self.column_xs(self.data.iter().copied());
for (idx, col_x) in col_xs.take(self.columns.len()).enumerate() {
if col_x < view_x + working_x + gap {
@@ -2274,7 +2274,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
// HACK: pass a self.data iterator in manually as a workaround for the lack of method partial
// borrowing. Note that this method's return value does not borrow the entire &Self!
fn column_xs(&self, data: impl Iterator<Item = ColumnData>) -> impl Iterator<Item = f64> {
let gaps = self.options.gaps;
let gaps = self.options.layout.gaps;
let mut x = 0.;
// Chain with a dummy value to be able to get one past all columns' X.
@@ -2408,25 +2408,29 @@ impl<W: LayoutElement> ScrollingSpace<W> {
let mut hint_area = match position {
InsertPosition::NewColumn(column_index) => {
if column_index == 0 || column_index == self.columns.len() {
let size =
Size::from((300., self.working_area.size.h - self.options.gaps * 2.));
let size = Size::from((
300.,
self.working_area.size.h - self.options.layout.gaps * 2.,
));
let mut loc = Point::from((
self.column_x(column_index),
self.working_area.loc.y + self.options.gaps,
self.working_area.loc.y + self.options.layout.gaps,
));
if column_index == 0 && !self.columns.is_empty() {
loc.x -= size.w + self.options.gaps;
loc.x -= size.w + self.options.layout.gaps;
}
Rectangle::new(loc, size)
} else if column_index > self.columns.len() {
error!("insert hint column index is out of range");
return None;
} else {
let size =
Size::from((300., self.working_area.size.h - self.options.gaps * 2.));
let size = Size::from((
300.,
self.working_area.size.h - self.options.layout.gaps * 2.,
));
let loc = Point::from((
self.column_x(column_index) - size.w / 2. - self.options.gaps / 2.,
self.working_area.loc.y + self.options.gaps,
self.column_x(column_index) - size.w / 2. - self.options.layout.gaps / 2.,
self.working_area.loc.y + self.options.layout.gaps,
));
Rectangle::new(loc, size)
}
@@ -2462,9 +2466,9 @@ impl<W: LayoutElement> ScrollingSpace<W> {
if tile_index == 0 {
(150., top)
} else if tile_index == col.tiles.len() {
(150., top - self.options.gaps - 150.)
(150., top - self.options.layout.gaps - 150.)
} else {
(300., top - self.options.gaps / 2. - 150.)
(300., top - self.options.layout.gaps / 2. - 150.)
}
};
@@ -2716,7 +2720,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
let mut active_col_x = None;
let mut counted_non_active_column = false;
let gap = self.options.gaps;
let gap = self.options.layout.gaps;
let col_xs = self.column_xs(self.data.iter().copied());
for (idx, col_x) in col_xs.take(self.columns.len()).enumerate() {
if col_x < view_x + working_x + gap {
@@ -3051,7 +3055,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
let (leftmost, rightmost) = if self.columns.is_empty() {
(0., 0.)
} else {
let gaps = self.options.gaps;
let gaps = self.options.layout.gaps;
let mut leftmost = -self.working_area.size.w;
@@ -3147,17 +3151,17 @@ impl<W: LayoutElement> ScrollingSpace<W> {
};
snapping_points.push(Snap { view_pos, col_idx });
col_x += col_w + self.options.gaps;
col_x += col_w + self.options.layout.gaps;
}
} else {
let center_on_overflow = matches!(
self.options.center_focused_column,
self.options.layout.center_focused_column,
CenterFocusedColumn::OnOverflow
);
let view_width = self.view_size.w;
let working_area_width = self.working_area.size.w;
let gaps = self.options.gaps;
let gaps = self.options.layout.gaps;
let snap_points =
|col_x, col: &Column<W>, prev_col_w: Option<f64>, next_col_w: Option<f64>| {
@@ -3297,8 +3301,8 @@ impl<W: LayoutElement> ScrollingSpace<W> {
break;
}
} else {
let padding =
((self.working_area.size.w - col_w) / 2.).clamp(0., self.options.gaps);
let padding = ((self.working_area.size.w - col_w) / 2.)
.clamp(0., self.options.layout.gaps);
if target_snap.view_pos + left_strut + self.working_area.size.w
< col_x + col_w + padding
{
@@ -3319,8 +3323,8 @@ impl<W: LayoutElement> ScrollingSpace<W> {
break;
}
} else {
let padding =
((self.working_area.size.w - col_w) / 2.).clamp(0., self.options.gaps);
let padding = ((self.working_area.size.w - col_w) / 2.)
.clamp(0., self.options.layout.gaps);
if col_x - padding < target_snap.view_pos + left_strut {
break;
}
@@ -3548,12 +3552,12 @@ impl<W: LayoutElement> ScrollingSpace<W> {
win.set_interactive_resize(col_resize_data);
let border_config = self.options.border.merged_with(&win.rules().border);
let border_config = self.options.layout.border.merged_with(&win.rules().border);
let bounds = compute_toplevel_bounds(
border_config,
self.working_area.size,
extra_size,
self.options.gaps,
self.options.layout.gaps,
);
win.set_bounds(bounds);
@@ -3614,7 +3618,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
assert_eq!(self.columns.len(), self.data.len());
assert_eq!(
self.working_area,
compute_working_area(self.parent_area, self.scale, self.options.struts)
compute_working_area(self.parent_area, self.scale, self.options.layout.struts)
);
if !self.columns.is_empty() {
@@ -3802,7 +3806,7 @@ impl<W: LayoutElement> Column<W> {
.window()
.rules()
.default_column_display
.unwrap_or(options.default_column_display);
.unwrap_or(options.layout.default_column_display);
let mut rv = Self {
tiles: vec![],
@@ -3813,7 +3817,7 @@ impl<W: LayoutElement> Column<W> {
is_full_width,
is_pending_fullscreen: false,
display_mode,
tab_indicator: TabIndicator::new(options.tab_indicator),
tab_indicator: TabIndicator::new(options.layout.tab_indicator),
move_animation: None,
view_size,
working_area,
@@ -3832,7 +3836,7 @@ impl<W: LayoutElement> Column<W> {
// Animate the tab indicator for new columns.
if display_mode == ColumnDisplay::Tabbed
&& !rv.options.tab_indicator.hide_when_single_tab
&& !rv.options.layout.tab_indicator.hide_when_single_tab
&& !rv.is_fullscreen()
{
// Usually new columns are created together with window movement actions. For new
@@ -3858,27 +3862,27 @@ impl<W: LayoutElement> Column<W> {
}
// If preset widths changed, clear our stored preset index.
if self.options.preset_column_widths != options.preset_column_widths {
if self.options.layout.preset_column_widths != options.layout.preset_column_widths {
self.preset_width_idx = None;
}
// If preset heights changed, make our heights non-preset.
if self.options.preset_window_heights != options.preset_window_heights {
if self.options.layout.preset_window_heights != options.layout.preset_window_heights {
self.convert_heights_to_auto();
update_sizes = true;
}
if self.options.gaps != options.gaps {
if self.options.layout.gaps != options.layout.gaps {
update_sizes = true;
}
if self.options.border.off != options.border.off
|| self.options.border.width != options.border.width
if self.options.layout.border.off != options.layout.border.off
|| self.options.layout.border.width != options.layout.border.width
{
update_sizes = true;
}
if self.options.tab_indicator != options.tab_indicator {
if self.options.layout.tab_indicator != options.layout.tab_indicator {
update_sizes = true;
}
@@ -3887,7 +3891,8 @@ impl<W: LayoutElement> Column<W> {
data.update(tile);
}
self.tab_indicator.update_config(options.tab_indicator);
self.tab_indicator
.update_config(options.layout.tab_indicator);
self.view_size = view_size;
self.working_area = working_area;
self.scale = scale;
@@ -4192,7 +4197,7 @@ impl<W: LayoutElement> Column<W> {
fn resolve_column_width(&self, width: ColumnWidth) -> f64 {
let working_size = self.working_area.size;
let gaps = self.options.gaps;
let gaps = self.options.layout.gaps;
let extra = self.extra_size();
match width {
@@ -4274,7 +4279,7 @@ impl<W: LayoutElement> Column<W> {
let width = self.resolve_column_width(width);
let width = f64::max(f64::min(width, max_width), min_width);
let max_tile_height = working_size.h - self.options.gaps * 2. - extra_size.h;
let max_tile_height = working_size.h - self.options.layout.gaps * 2. - extra_size.h;
// If there are multiple windows in a column, clamp the non-auto window's height according
// to other windows' min sizes.
@@ -4289,7 +4294,7 @@ impl<W: LayoutElement> Column<W> {
.iter()
.enumerate()
.filter(|(idx, _)| *idx != non_auto_idx)
.map(|(_, min_size)| min_size.h + self.options.gaps)
.map(|(_, min_size)| min_size.h + self.options.layout.gaps)
.sum::<f64>();
let tile = &self.tiles[non_auto_idx];
@@ -4318,7 +4323,7 @@ impl<W: LayoutElement> Column<W> {
WindowHeight::Fixed(tile.tile_height_for_window_height(window_height))
}
WindowHeight::Preset(idx) => {
let preset = self.options.preset_window_heights[idx];
let preset = self.options.layout.preset_window_heights[idx];
let window_height = match self.resolve_preset_height(preset) {
ResolvedSize::Tile(h) => tile.window_height_for_tile_height(h),
ResolvedSize::Window(h) => h,
@@ -4366,7 +4371,7 @@ impl<W: LayoutElement> Column<W> {
// The following logic will apply individual min/max height, etc.
}
let gaps_left = self.options.gaps * (self.tiles.len() + 1) as f64;
let gaps_left = self.options.layout.gaps * (self.tiles.len() + 1) as f64;
let mut height_left = working_size.h - gaps_left;
let mut auto_tiles_left = self.tiles.len();
@@ -4589,7 +4594,7 @@ impl<W: LayoutElement> Column<W> {
self.preset_width_idx
};
let len = self.options.preset_column_widths.len();
let len = self.options.layout.preset_column_widths.len();
let preset_idx = if let Some(idx) = preset_idx {
(idx + if forwards { 1 } else { len - 1 }) % len
} else {
@@ -4599,6 +4604,7 @@ impl<W: LayoutElement> Column<W> {
let mut it = self
.options
.layout
.preset_column_widths
.iter()
.map(|preset| self.resolve_preset_width(*preset));
@@ -4624,7 +4630,7 @@ impl<W: LayoutElement> Column<W> {
}
};
let preset = self.options.preset_column_widths[preset_idx];
let preset = self.options.layout.preset_column_widths[preset_idx];
self.set_column_width(SizeChange::from(preset), Some(tile_idx), true);
self.preset_width_idx = Some(preset_idx);
@@ -4672,11 +4678,11 @@ impl<W: LayoutElement> Column<W> {
ColumnWidth::Proportion(proportion)
}
(ColumnWidth::Fixed(_), SizeChange::AdjustProportion(delta)) => {
let full = self.working_area.size.w - self.options.gaps;
let full = self.working_area.size.w - self.options.layout.gaps;
let current = if full == 0. {
1.
} else {
(current_px + self.options.gaps + self.extra_size().w) / full
(current_px + self.options.layout.gaps + self.extra_size().w) / full
};
let proportion = (current + delta / 100.).clamp(0., MAX_F);
ColumnWidth::Proportion(proportion)
@@ -4710,7 +4716,7 @@ impl<W: LayoutElement> Column<W> {
let current_tile_px = tile.tile_height_for_window_height(current_window_px);
let working_size = self.working_area.size.h;
let gaps = self.options.gaps;
let gaps = self.options.layout.gaps;
let extra_size = self.extra_size().h;
let full = working_size - gaps;
let current_prop = if full == 0. {
@@ -4794,7 +4800,7 @@ impl<W: LayoutElement> Column<W> {
self.convert_heights_to_auto();
}
let len = self.options.preset_window_heights.len();
let len = self.options.layout.preset_window_heights.len();
let preset_idx = match self.data[tile_idx].height {
WindowHeight::Preset(idx) => (idx + if forwards { 1 } else { len - 1 }) % len,
_ => {
@@ -4803,6 +4809,7 @@ impl<W: LayoutElement> Column<W> {
let mut it = self
.options
.layout
.preset_window_heights
.iter()
.copied()
@@ -4933,7 +4940,7 @@ impl<W: LayoutElement> Column<W> {
return origin;
}
origin.y += self.working_area.loc.y + self.options.gaps;
origin.y += self.working_area.loc.y + self.options.layout.gaps;
if self.display_mode == ColumnDisplay::Tabbed {
origin += self
@@ -4953,8 +4960,8 @@ impl<W: LayoutElement> Column<W> {
// FIXME: this should take into account always-center-single-column, which means that
// Column should somehow know when it is being centered due to being the single column on
// the workspace or some other reason.
let center = self.options.center_focused_column == CenterFocusedColumn::Always;
let gaps = self.options.gaps;
let center = self.options.layout.center_focused_column == CenterFocusedColumn::Always;
let gaps = self.options.layout.gaps;
let tabbed = self.display_mode == ColumnDisplay::Tabbed;
// Does not include extra size from the tab indicator.
@@ -5117,7 +5124,7 @@ impl<W: LayoutElement> Column<W> {
}
if let Some(idx) = self.preset_width_idx {
assert!(idx < self.options.preset_column_widths.len());
assert!(idx < self.options.layout.preset_column_widths.len());
}
let is_tabbed = self.display_mode == ColumnDisplay::Tabbed;
@@ -5134,7 +5141,7 @@ impl<W: LayoutElement> Column<W> {
let working_size = self.working_area.size;
let extra_size = self.extra_size();
let gaps = self.options.gaps;
let gaps = self.options.layout.gaps;
let mut found_fixed = false;
let mut total_height = 0.;
@@ -5163,7 +5170,7 @@ impl<W: LayoutElement> Column<W> {
}
if let WindowHeight::Preset(idx) = data.height {
assert!(self.options.preset_window_heights.len() > idx);
assert!(self.options.layout.preset_window_heights.len() > idx);
}
let requested_size = tile.window().requested_size().unwrap();
@@ -5312,9 +5319,9 @@ fn resolve_preset_size(
extra_size: f64,
) -> ResolvedSize {
match preset {
PresetSize::Proportion(proportion) => {
ResolvedSize::Tile((view_size - options.gaps) * proportion - options.gaps - extra_size)
}
PresetSize::Proportion(proportion) => ResolvedSize::Tile(
(view_size - options.layout.gaps) * proportion - options.layout.gaps - extra_size,
),
PresetSize::Fixed(width) => ResolvedSize::Window(f64::from(width)),
}
}

View File

@@ -2,7 +2,8 @@ use std::cell::{Cell, OnceCell, RefCell};
use niri_config::workspace::WorkspaceName;
use niri_config::{
FloatOrInt, OutputName, TabIndicatorLength, TabIndicatorPosition, WorkspaceReference,
CenterFocusedColumn, FloatOrInt, OutputName, Struts, TabIndicatorLength, TabIndicatorPosition,
WorkspaceReference,
};
use proptest::prelude::*;
use proptest_derive::Arbitrary;
@@ -2066,8 +2067,8 @@ fn large_negative_height_change() {
];
let mut options = Options::default();
options.border.off = false;
options.border.width = 1.;
options.layout.border.off = false;
options.layout.border.width = 1.;
check_ops_with_options(options, ops);
}
@@ -2085,8 +2086,8 @@ fn large_max_size() {
];
let mut options = Options::default();
options.border.off = false;
options.border.width = 1.;
options.layout.border.off = false;
options.layout.border.width = 1.;
check_ops_with_options(options, ops);
}
@@ -2244,7 +2245,10 @@ fn open_right_of_on_different_workspace_ewaf() {
];
let options = Options {
empty_workspace_above_first: true,
layout: niri_config::Layout {
empty_workspace_above_first: true,
..Default::default()
},
..Default::default()
};
let layout = check_ops_with_options(options, ops);
@@ -2306,11 +2310,7 @@ fn config_change_updates_cached_sizes() {
}
.apply(&mut layout);
config
.layout
.border
.get_or_insert_with(Default::default)
.width = Some(FloatOrInt(4.));
config.layout.border.as_mut().unwrap().width = Some(FloatOrInt(4.));
layout.update_config(&config);
layout.verify_invariants();
@@ -2427,12 +2427,15 @@ fn fixed_height_takes_max_non_auto_into_account() {
];
let options = Options {
border: niri_config::Border {
off: false,
width: 4.,
layout: niri_config::Layout {
border: niri_config::Border {
off: false,
width: 4.,
..Default::default()
},
gaps: 0.,
..Default::default()
},
gaps: 0.,
..Default::default()
};
check_ops_with_options(options, ops);
@@ -2511,7 +2514,10 @@ fn interactive_move_onto_empty_output_ewaf() {
];
let options = Options {
empty_workspace_above_first: true,
layout: niri_config::Layout {
empty_workspace_above_first: true,
..Default::default()
},
..Default::default()
};
check_ops_with_options(options, ops);
@@ -2572,7 +2578,10 @@ fn interactive_move_onto_first_empty_workspace() {
Op::InteractiveMoveEnd { window: 1 },
];
let options = Options {
empty_workspace_above_first: true,
layout: niri_config::Layout {
empty_workspace_above_first: true,
..Default::default()
},
..Default::default()
};
check_ops_with_options(options, ops);
@@ -2653,7 +2662,10 @@ fn named_workspace_to_output_ewaf() {
Op::AddOutput(2),
];
let options = Options {
empty_workspace_above_first: true,
layout: niri_config::Layout {
empty_workspace_above_first: true,
..Default::default()
},
..Default::default()
};
check_ops_with_options(options, ops);
@@ -2672,7 +2684,10 @@ fn move_window_to_empty_workspace_above_first() {
Op::MoveWorkspaceDown,
];
let options = Options {
empty_workspace_above_first: true,
layout: niri_config::Layout {
empty_workspace_above_first: true,
..Default::default()
},
..Default::default()
};
check_ops_with_options(options, ops);
@@ -2689,7 +2704,10 @@ fn move_window_to_different_output() {
Op::MoveWorkspaceToOutput(2),
];
let options = Options {
empty_workspace_above_first: true,
layout: niri_config::Layout {
empty_workspace_above_first: true,
..Default::default()
},
..Default::default()
};
check_ops_with_options(options, ops);
@@ -2705,7 +2723,10 @@ fn close_window_empty_ws_above_first() {
Op::CloseWindow(1),
];
let options = Options {
empty_workspace_above_first: true,
layout: niri_config::Layout {
empty_workspace_above_first: true,
..Default::default()
},
..Default::default()
};
check_ops_with_options(options, ops);
@@ -2722,7 +2743,10 @@ fn add_and_remove_output() {
Op::RemoveOutput(2),
];
let options = Options {
empty_workspace_above_first: true,
layout: niri_config::Layout {
empty_workspace_above_first: true,
..Default::default()
},
..Default::default()
};
check_ops_with_options(options, ops);
@@ -2739,7 +2763,10 @@ fn switch_ewaf_on() {
let mut layout = check_ops(ops);
layout.update_options(Options {
empty_workspace_above_first: true,
layout: niri_config::Layout {
empty_workspace_above_first: true,
..Default::default()
},
..Default::default()
});
layout.verify_invariants();
@@ -2755,7 +2782,10 @@ fn switch_ewaf_off() {
];
let options = Options {
empty_workspace_above_first: true,
layout: niri_config::Layout {
empty_workspace_above_first: true,
..Default::default()
},
..Default::default()
};
let mut layout = check_ops_with_options(options, ops);
@@ -3074,7 +3104,10 @@ fn set_first_workspace_name_ewaf() {
];
let options = Options {
empty_workspace_above_first: true,
layout: niri_config::Layout {
empty_workspace_above_first: true,
..Default::default()
},
..Default::default()
};
check_ops_with_options(options, ops);
@@ -3165,7 +3198,10 @@ fn preset_column_width_fixed_correct_with_border() {
];
let options = Options {
preset_column_widths: vec![PresetSize::Fixed(500)],
layout: niri_config::Layout {
preset_column_widths: vec![PresetSize::Fixed(500)],
..Default::default()
},
..Default::default()
};
let mut layout = check_ops_with_options(options, ops);
@@ -3175,10 +3211,13 @@ fn preset_column_width_fixed_correct_with_border() {
// Add border.
let options = Options {
preset_column_widths: vec![PresetSize::Fixed(500)],
border: niri_config::Border {
off: false,
width: 5.,
layout: niri_config::Layout {
preset_column_widths: vec![PresetSize::Fixed(500)],
border: niri_config::Border {
off: false,
width: 5.,
..Default::default()
},
..Default::default()
},
..Default::default()
@@ -3211,7 +3250,10 @@ fn preset_column_width_reset_after_set_width() {
];
let options = Options {
preset_column_widths: vec![PresetSize::Fixed(500), PresetSize::Fixed(1000)],
layout: niri_config::Layout {
preset_column_widths: vec![PresetSize::Fixed(500), PresetSize::Fixed(1000)],
..Default::default()
},
..Default::default()
};
let layout = check_ops_with_options(options, ops);
@@ -3469,7 +3511,7 @@ prop_compose! {
}
prop_compose! {
fn arbitrary_options()(
fn arbitrary_layout_config()(
gaps in arbitrary_spacing(),
struts in arbitrary_struts(),
focus_ring in arbitrary_focus_ring(),
@@ -3479,8 +3521,8 @@ prop_compose! {
center_focused_column in arbitrary_center_focused_column(),
always_center_single_column in any::<bool>(),
empty_workspace_above_first in any::<bool>(),
) -> Options {
Options {
) -> niri_config::Layout {
niri_config::Layout {
gaps,
struts,
center_focused_column,
@@ -3495,6 +3537,17 @@ prop_compose! {
}
}
prop_compose! {
fn arbitrary_options()(
layout in arbitrary_layout_config()
) -> Options {
Options {
layout,
..Default::default()
}
}
}
proptest! {
#![proptest_config(ProptestConfig {
cases: if std::env::var_os("RUN_SLOW_TESTS").is_none() {

View File

@@ -29,7 +29,10 @@ fn make_options() -> Options {
});
let mut options = Options {
gaps: 0.0,
layout: niri_config::Layout {
gaps: 0.0,
..Default::default()
},
..Options::default()
};
options.animations.window_resize.anim.kind = LINEAR;

View File

@@ -188,9 +188,12 @@ fn unfullscreen_with_large_border() {
];
let options = Options {
border: niri_config::Border {
off: false,
width: 10000.,
layout: niri_config::Layout {
border: niri_config::Border {
off: false,
width: 10000.,
..Default::default()
},
..Default::default()
},
..Default::default()

View File

@@ -175,9 +175,9 @@ impl<W: LayoutElement> Tile<W> {
options: Rc<Options>,
) -> Self {
let rules = window.rules();
let border_config = options.border.merged_with(&rules.border);
let focus_ring_config = options.focus_ring.merged_with(&rules.focus_ring);
let shadow_config = options.shadow.merged_with(&rules.shadow);
let border_config = options.layout.border.merged_with(&rules.border);
let focus_ring_config = options.layout.focus_ring.merged_with(&rules.focus_ring);
let shadow_config = options.layout.shadow.merged_with(&rules.shadow);
let is_fullscreen = window.is_fullscreen();
Self {
@@ -214,10 +214,10 @@ impl<W: LayoutElement> Tile<W> {
options: Rc<Options>,
) {
// If preset widths or heights changed, clear our stored preset index.
if self.options.preset_column_widths != options.preset_column_widths {
if self.options.layout.preset_column_widths != options.layout.preset_column_widths {
self.floating_preset_width_idx = None;
}
if self.options.preset_window_heights != options.preset_window_heights {
if self.options.layout.preset_window_heights != options.layout.preset_window_heights {
self.floating_preset_height_idx = None;
}
@@ -227,13 +227,17 @@ impl<W: LayoutElement> Tile<W> {
let rules = self.window.rules();
let border_config = self.options.border.merged_with(&rules.border);
let border_config = self.options.layout.border.merged_with(&rules.border);
self.border.update_config(border_config.into());
let focus_ring_config = self.options.focus_ring.merged_with(&rules.focus_ring);
let focus_ring_config = self
.options
.layout
.focus_ring
.merged_with(&rules.focus_ring);
self.focus_ring.update_config(focus_ring_config);
let shadow_config = self.options.shadow.merged_with(&rules.shadow);
let shadow_config = self.options.layout.shadow.merged_with(&rules.shadow);
self.shadow.update_config(shadow_config);
}
@@ -332,12 +336,16 @@ impl<W: LayoutElement> Tile<W> {
}
let rules = self.window.rules();
let border_config = self.options.border.merged_with(&rules.border);
let border_config = self.options.layout.border.merged_with(&rules.border);
self.border.update_config(border_config.into());
let focus_ring_config = self.options.focus_ring.merged_with(&rules.focus_ring);
let focus_ring_config = self
.options
.layout
.focus_ring
.merged_with(&rules.focus_ring);
self.focus_ring.update_config(focus_ring_config);
let shadow_config = self.options.shadow.merged_with(&rules.shadow);
let shadow_config = self.options.layout.shadow.merged_with(&rules.shadow);
self.shadow.update_config(shadow_config);
let window_size = self.window_size();

View File

@@ -754,7 +754,7 @@ impl<W: LayoutElement> Workspace<W> {
Some(Some(width)) => Some(width),
Some(None) => None,
None if is_floating => None,
None => self.options.default_column_width,
None => self.options.layout.default_column_width,
}
}
@@ -1272,11 +1272,12 @@ impl<W: LayoutElement> Workspace<W> {
// Come up with a default floating position close to the tile position.
let stored_or_default = self.floating.stored_or_default_tile_pos(&removed.tile);
if stored_or_default.is_none() {
let offset = if self.options.center_focused_column == CenterFocusedColumn::Always {
Point::from((0., 0.))
} else {
Point::from((50., 50.))
};
let offset =
if self.options.layout.center_focused_column == CenterFocusedColumn::Always {
Point::from((0., 0.))
} else {
Point::from((50., 50.))
};
let pos = render_pos + offset;
let size = removed.tile.tile_size();
let pos = self.floating.clamp_within_working_area(pos, size);