mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-23 02:05:33 +07:00
Refactor layout for configurability, add preset-column-widths option
layout.rs finally gets a struct actually named Layout.
This commit is contained in:
@@ -93,6 +93,19 @@ cursor {
|
|||||||
// If the client will specifically ask for CSD, the request will be honored.
|
// If the client will specifically ask for CSD, the request will be honored.
|
||||||
// prefer-no-csd
|
// prefer-no-csd
|
||||||
|
|
||||||
|
// You can customize the widths that "switch-preset-column-width" (Mod+R) toggles between.
|
||||||
|
preset-column-widths {
|
||||||
|
// Proportion sets the width as a fraction of the output width, taking gaps into account.
|
||||||
|
// For example, you can perfectly fit four windows sized "proportion 0.25" on an output.
|
||||||
|
// The default preset widths are 1/3, 1/2 and 2/3 of the output.
|
||||||
|
proportion 0.333
|
||||||
|
proportion 0.5
|
||||||
|
proportion 0.667
|
||||||
|
|
||||||
|
// Fixed sets the width in logical pixels exactly.
|
||||||
|
// fixed 1920
|
||||||
|
}
|
||||||
|
|
||||||
binds {
|
binds {
|
||||||
// Keys consist of modifiers separated by + signs, followed by an XKB key name
|
// Keys consist of modifiers separated by + signs, followed by an XKB key name
|
||||||
// in the end. To find an XKB name for a particular key, you may use a program
|
// in the end. To find an XKB name for a particular key, you may use a program
|
||||||
|
|||||||
+22
-1
@@ -22,6 +22,8 @@ pub struct Config {
|
|||||||
pub prefer_no_csd: bool,
|
pub prefer_no_csd: bool,
|
||||||
#[knuffel(child, default)]
|
#[knuffel(child, default)]
|
||||||
pub cursor: Cursor,
|
pub cursor: Cursor,
|
||||||
|
#[knuffel(child, unwrap(children), default)]
|
||||||
|
pub preset_column_widths: Vec<PresetWidth>,
|
||||||
#[knuffel(child, default)]
|
#[knuffel(child, default)]
|
||||||
pub binds: Binds,
|
pub binds: Binds,
|
||||||
#[knuffel(child, default)]
|
#[knuffel(child, default)]
|
||||||
@@ -125,7 +127,7 @@ pub struct SpawnAtStartup {
|
|||||||
pub command: Vec<String>,
|
pub command: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(knuffel::Decode, Debug, Clone, PartialEq)]
|
#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct FocusRing {
|
pub struct FocusRing {
|
||||||
#[knuffel(child)]
|
#[knuffel(child)]
|
||||||
pub off: bool,
|
pub off: bool,
|
||||||
@@ -189,6 +191,12 @@ impl Default for Cursor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum PresetWidth {
|
||||||
|
Proportion(#[knuffel(argument)] f64),
|
||||||
|
Fixed(#[knuffel(argument)] i32),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(knuffel::Decode, Debug, Default, PartialEq)]
|
#[derive(knuffel::Decode, Debug, Default, PartialEq)]
|
||||||
pub struct Binds(#[knuffel(children)] pub Vec<Bind>);
|
pub struct Binds(#[knuffel(children)] pub Vec<Bind>);
|
||||||
|
|
||||||
@@ -513,6 +521,13 @@ mod tests {
|
|||||||
xcursor-size 16
|
xcursor-size 16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preset-column-widths {
|
||||||
|
proportion 0.25
|
||||||
|
proportion 0.5
|
||||||
|
fixed 960
|
||||||
|
fixed 1280
|
||||||
|
}
|
||||||
|
|
||||||
binds {
|
binds {
|
||||||
Mod+T { spawn "alacritty"; }
|
Mod+T { spawn "alacritty"; }
|
||||||
Mod+Q { close-window; }
|
Mod+Q { close-window; }
|
||||||
@@ -580,6 +595,12 @@ mod tests {
|
|||||||
xcursor_theme: String::from("breeze_cursors"),
|
xcursor_theme: String::from("breeze_cursors"),
|
||||||
xcursor_size: 16,
|
xcursor_size: 16,
|
||||||
},
|
},
|
||||||
|
preset_column_widths: vec![
|
||||||
|
PresetWidth::Proportion(0.25),
|
||||||
|
PresetWidth::Proportion(0.5),
|
||||||
|
PresetWidth::Fixed(960),
|
||||||
|
PresetWidth::Fixed(1280),
|
||||||
|
],
|
||||||
binds: Binds(vec![
|
binds: Binds(vec![
|
||||||
Bind {
|
Bind {
|
||||||
key: Key {
|
key: Key {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ impl CompositorHandler for State {
|
|||||||
let window = entry.remove();
|
let window = entry.remove();
|
||||||
window.on_commit();
|
window.on_commit();
|
||||||
|
|
||||||
if let Some(output) = self.niri.monitor_set.add_window(window, true).cloned() {
|
if let Some(output) = self.niri.layout.add_window(window, true).cloned() {
|
||||||
self.niri.queue_redraw(output);
|
self.niri.queue_redraw(output);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -100,7 +100,7 @@ impl CompositorHandler for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is a commit of a previously-mapped root or a non-toplevel root.
|
// This is a commit of a previously-mapped root or a non-toplevel root.
|
||||||
if let Some((window, output)) = self.niri.monitor_set.find_window_and_output(surface) {
|
if let Some((window, output)) = self.niri.layout.find_window_and_output(surface) {
|
||||||
// This is a commit of a previously-mapped toplevel.
|
// This is a commit of a previously-mapped toplevel.
|
||||||
window.on_commit();
|
window.on_commit();
|
||||||
|
|
||||||
@@ -110,14 +110,14 @@ impl CompositorHandler for State {
|
|||||||
|
|
||||||
if !is_mapped {
|
if !is_mapped {
|
||||||
// The toplevel got unmapped.
|
// The toplevel got unmapped.
|
||||||
self.niri.monitor_set.remove_window(&window);
|
self.niri.layout.remove_window(&window);
|
||||||
self.niri.unmapped_windows.insert(surface.clone(), window);
|
self.niri.unmapped_windows.insert(surface.clone(), window);
|
||||||
self.niri.queue_redraw(output);
|
self.niri.queue_redraw(output);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The toplevel remains mapped.
|
// The toplevel remains mapped.
|
||||||
self.niri.monitor_set.update_window(&window);
|
self.niri.layout.update_window(&window);
|
||||||
|
|
||||||
self.niri.queue_redraw(output);
|
self.niri.queue_redraw(output);
|
||||||
return;
|
return;
|
||||||
@@ -127,10 +127,10 @@ impl CompositorHandler for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is a commit of a non-root or a non-toplevel root.
|
// This is a commit of a non-root or a non-toplevel root.
|
||||||
let root_window_output = self.niri.monitor_set.find_window_and_output(&root_surface);
|
let root_window_output = self.niri.layout.find_window_and_output(&root_surface);
|
||||||
if let Some((window, output)) = root_window_output {
|
if let Some((window, output)) = root_window_output {
|
||||||
window.on_commit();
|
window.on_commit();
|
||||||
self.niri.monitor_set.update_window(&window);
|
self.niri.layout.update_window(&window);
|
||||||
self.niri.queue_redraw(output);
|
self.niri.queue_redraw(output);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -139,7 +139,7 @@ impl CompositorHandler for State {
|
|||||||
self.popups_handle_commit(surface);
|
self.popups_handle_commit(surface);
|
||||||
if let Some(popup) = self.niri.popups.find_popup(surface) {
|
if let Some(popup) = self.niri.popups.find_popup(surface) {
|
||||||
if let Ok(root) = find_popup_root_surface(&popup) {
|
if let Ok(root) = find_popup_root_surface(&popup) {
|
||||||
let root_window_output = self.niri.monitor_set.find_window_and_output(&root);
|
let root_window_output = self.niri.layout.find_window_and_output(&root);
|
||||||
if let Some((_window, output)) = root_window_output {
|
if let Some((_window, output)) = root_window_output {
|
||||||
self.niri.queue_redraw(output);
|
self.niri.queue_redraw(output);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ impl WlrLayerShellHandler for State {
|
|||||||
let output = wl_output
|
let output = wl_output
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(Output::from_resource)
|
.and_then(Output::from_resource)
|
||||||
.or_else(|| self.niri.monitor_set.active_output().cloned())
|
.or_else(|| self.niri.layout.active_output().cloned())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut map = layer_map_for_output(&output);
|
let mut map = layer_map_for_output(&output);
|
||||||
map.map_layer(&LayerSurface::new(surface, namespace))
|
map.map_layer(&LayerSurface::new(surface, namespace))
|
||||||
@@ -35,7 +35,7 @@ impl WlrLayerShellHandler for State {
|
|||||||
|
|
||||||
fn layer_destroyed(&mut self, surface: WlrLayerSurface) {
|
fn layer_destroyed(&mut self, surface: WlrLayerSurface) {
|
||||||
let output = if let Some((output, mut map, layer)) =
|
let output = if let Some((output, mut map, layer)) =
|
||||||
self.niri.monitor_set.outputs().find_map(|o| {
|
self.niri.layout.outputs().find_map(|o| {
|
||||||
let map = layer_map_for_output(o);
|
let map = layer_map_for_output(o);
|
||||||
let layer = map
|
let layer = map
|
||||||
.layers()
|
.layers()
|
||||||
@@ -59,7 +59,7 @@ impl State {
|
|||||||
pub fn layer_shell_handle_commit(&mut self, surface: &WlSurface) {
|
pub fn layer_shell_handle_commit(&mut self, surface: &WlSurface) {
|
||||||
let Some(output) = self
|
let Some(output) = self
|
||||||
.niri
|
.niri
|
||||||
.monitor_set
|
.layout
|
||||||
.outputs()
|
.outputs()
|
||||||
.find(|o| {
|
.find(|o| {
|
||||||
let map = layer_map_for_output(o);
|
let map = layer_map_for_output(o);
|
||||||
|
|||||||
+1
-1
@@ -65,7 +65,7 @@ impl InputMethodHandler for State {
|
|||||||
}
|
}
|
||||||
fn parent_geometry(&self, parent: &WlSurface) -> Rectangle<i32, Logical> {
|
fn parent_geometry(&self, parent: &WlSurface) -> Rectangle<i32, Logical> {
|
||||||
self.niri
|
self.niri
|
||||||
.monitor_set
|
.layout
|
||||||
.find_window_and_output(parent)
|
.find_window_and_output(parent)
|
||||||
.map(|(window, _)| window.geometry())
|
.map(|(window, _)| window.geometry())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
|
|||||||
+12
-13
@@ -1,4 +1,4 @@
|
|||||||
use smithay::desktop::{find_popup_root_surface, layer_map_for_output, PopupKind, Window};
|
use smithay::desktop::{find_popup_root_surface, PopupKind, Window};
|
||||||
use smithay::output::Output;
|
use smithay::output::Output;
|
||||||
use smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1;
|
use smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1;
|
||||||
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::{self, ResizeEdge};
|
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::{self, ResizeEdge};
|
||||||
@@ -15,7 +15,6 @@ use smithay::wayland::shell::xdg::{
|
|||||||
};
|
};
|
||||||
use smithay::{delegate_kde_decoration, delegate_xdg_decoration, delegate_xdg_shell};
|
use smithay::{delegate_kde_decoration, delegate_xdg_decoration, delegate_xdg_shell};
|
||||||
|
|
||||||
use crate::layout::configure_new_window;
|
|
||||||
use crate::niri::State;
|
use crate::niri::State;
|
||||||
|
|
||||||
impl XdgShellHandler for State {
|
impl XdgShellHandler for State {
|
||||||
@@ -28,9 +27,9 @@ impl XdgShellHandler for State {
|
|||||||
let window = Window::new(surface);
|
let window = Window::new(surface);
|
||||||
|
|
||||||
// Tell the surface the preferred size and bounds for its likely output.
|
// Tell the surface the preferred size and bounds for its likely output.
|
||||||
let output = self.niri.monitor_set.active_output().unwrap();
|
if let Some(ws) = self.niri.layout.active_workspace() {
|
||||||
let working_area = layer_map_for_output(output).non_exclusive_zone();
|
ws.configure_new_window(&window);
|
||||||
configure_new_window(working_area, &window);
|
}
|
||||||
|
|
||||||
// At the moment of creation, xdg toplevels must have no buffer.
|
// At the moment of creation, xdg toplevels must have no buffer.
|
||||||
let existing = self.niri.unmapped_windows.insert(wl_surface, window);
|
let existing = self.niri.unmapped_windows.insert(wl_surface, window);
|
||||||
@@ -106,18 +105,18 @@ impl XdgShellHandler for State {
|
|||||||
// independently from its buffer size
|
// independently from its buffer size
|
||||||
if let Some((window, current_output)) = self
|
if let Some((window, current_output)) = self
|
||||||
.niri
|
.niri
|
||||||
.monitor_set
|
.layout
|
||||||
.find_window_and_output(surface.wl_surface())
|
.find_window_and_output(surface.wl_surface())
|
||||||
{
|
{
|
||||||
if let Some(requested_output) = wl_output.as_ref().and_then(Output::from_resource) {
|
if let Some(requested_output) = wl_output.as_ref().and_then(Output::from_resource) {
|
||||||
if requested_output != current_output {
|
if requested_output != current_output {
|
||||||
self.niri
|
self.niri
|
||||||
.monitor_set
|
.layout
|
||||||
.move_window_to_output(window.clone(), &requested_output);
|
.move_window_to_output(window.clone(), &requested_output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.niri.monitor_set.set_fullscreen(&window, true);
|
self.niri.layout.set_fullscreen(&window, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,10 +128,10 @@ impl XdgShellHandler for State {
|
|||||||
fn unfullscreen_request(&mut self, surface: ToplevelSurface) {
|
fn unfullscreen_request(&mut self, surface: ToplevelSurface) {
|
||||||
if let Some((window, _)) = self
|
if let Some((window, _)) = self
|
||||||
.niri
|
.niri
|
||||||
.monitor_set
|
.layout
|
||||||
.find_window_and_output(surface.wl_surface())
|
.find_window_and_output(surface.wl_surface())
|
||||||
{
|
{
|
||||||
self.niri.monitor_set.set_fullscreen(&window, false);
|
self.niri.layout.set_fullscreen(&window, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,16 +148,16 @@ impl XdgShellHandler for State {
|
|||||||
|
|
||||||
let (window, output) = self
|
let (window, output) = self
|
||||||
.niri
|
.niri
|
||||||
.monitor_set
|
.layout
|
||||||
.find_window_and_output(surface.wl_surface())
|
.find_window_and_output(surface.wl_surface())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.niri.monitor_set.remove_window(&window);
|
self.niri.layout.remove_window(&window);
|
||||||
self.niri.queue_redraw(output);
|
self.niri.queue_redraw(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn popup_destroyed(&mut self, surface: PopupSurface) {
|
fn popup_destroyed(&mut self, surface: PopupSurface) {
|
||||||
if let Ok(root) = find_popup_root_surface(&surface.into()) {
|
if let Ok(root) = find_popup_root_surface(&surface.into()) {
|
||||||
let root_window_output = self.niri.monitor_set.find_window_and_output(&root);
|
let root_window_output = self.niri.layout.find_window_and_output(&root);
|
||||||
if let Some((_window, output)) = root_window_output {
|
if let Some((_window, output)) = root_window_output {
|
||||||
self.niri.queue_redraw(output);
|
self.niri.queue_redraw(output);
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-38
@@ -101,9 +101,7 @@ impl State {
|
|||||||
// doesn't always trigger due to damage, etc. So run it here right before it might prove
|
// doesn't always trigger due to damage, etc. So run it here right before it might prove
|
||||||
// important. Besides, animations affect the input, so it's best to have up-to-date values
|
// important. Besides, animations affect the input, so it's best to have up-to-date values
|
||||||
// here.
|
// here.
|
||||||
self.niri
|
self.niri.layout.advance_animations(get_monotonic_time());
|
||||||
.monitor_set
|
|
||||||
.advance_animations(get_monotonic_time());
|
|
||||||
|
|
||||||
let comp_mod = self.backend.mod_key();
|
let comp_mod = self.backend.mod_key();
|
||||||
|
|
||||||
@@ -150,7 +148,7 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::Screenshot => {
|
Action::Screenshot => {
|
||||||
let active = self.niri.monitor_set.active_output().cloned();
|
let active = self.niri.layout.active_output().cloned();
|
||||||
if let Some(active) = active {
|
if let Some(active) = active {
|
||||||
if let Some(renderer) = self.backend.renderer() {
|
if let Some(renderer) = self.backend.renderer() {
|
||||||
if let Err(err) = self.niri.screenshot(renderer, &active) {
|
if let Err(err) = self.niri.screenshot(renderer, &active) {
|
||||||
@@ -160,144 +158,144 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::CloseWindow => {
|
Action::CloseWindow => {
|
||||||
if let Some(window) = self.niri.monitor_set.focus() {
|
if let Some(window) = self.niri.layout.focus() {
|
||||||
window.toplevel().send_close();
|
window.toplevel().send_close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::FullscreenWindow => {
|
Action::FullscreenWindow => {
|
||||||
let focus = self.niri.monitor_set.focus().cloned();
|
let focus = self.niri.layout.focus().cloned();
|
||||||
if let Some(window) = focus {
|
if let Some(window) = focus {
|
||||||
self.niri.monitor_set.toggle_fullscreen(&window);
|
self.niri.layout.toggle_fullscreen(&window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::MoveColumnLeft => {
|
Action::MoveColumnLeft => {
|
||||||
self.niri.monitor_set.move_left();
|
self.niri.layout.move_left();
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::MoveColumnRight => {
|
Action::MoveColumnRight => {
|
||||||
self.niri.monitor_set.move_right();
|
self.niri.layout.move_right();
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::MoveWindowDown => {
|
Action::MoveWindowDown => {
|
||||||
self.niri.monitor_set.move_down();
|
self.niri.layout.move_down();
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::MoveWindowUp => {
|
Action::MoveWindowUp => {
|
||||||
self.niri.monitor_set.move_up();
|
self.niri.layout.move_up();
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::FocusColumnLeft => {
|
Action::FocusColumnLeft => {
|
||||||
self.niri.monitor_set.focus_left();
|
self.niri.layout.focus_left();
|
||||||
}
|
}
|
||||||
Action::FocusColumnRight => {
|
Action::FocusColumnRight => {
|
||||||
self.niri.monitor_set.focus_right();
|
self.niri.layout.focus_right();
|
||||||
}
|
}
|
||||||
Action::FocusWindowDown => {
|
Action::FocusWindowDown => {
|
||||||
self.niri.monitor_set.focus_down();
|
self.niri.layout.focus_down();
|
||||||
}
|
}
|
||||||
Action::FocusWindowUp => {
|
Action::FocusWindowUp => {
|
||||||
self.niri.monitor_set.focus_up();
|
self.niri.layout.focus_up();
|
||||||
}
|
}
|
||||||
Action::MoveWindowToWorkspaceDown => {
|
Action::MoveWindowToWorkspaceDown => {
|
||||||
self.niri.monitor_set.move_to_workspace_down();
|
self.niri.layout.move_to_workspace_down();
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::MoveWindowToWorkspaceUp => {
|
Action::MoveWindowToWorkspaceUp => {
|
||||||
self.niri.monitor_set.move_to_workspace_up();
|
self.niri.layout.move_to_workspace_up();
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::MoveWindowToWorkspace(idx) => {
|
Action::MoveWindowToWorkspace(idx) => {
|
||||||
self.niri.monitor_set.move_to_workspace(idx);
|
self.niri.layout.move_to_workspace(idx);
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::FocusWorkspaceDown => {
|
Action::FocusWorkspaceDown => {
|
||||||
self.niri.monitor_set.switch_workspace_down();
|
self.niri.layout.switch_workspace_down();
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::FocusWorkspaceUp => {
|
Action::FocusWorkspaceUp => {
|
||||||
self.niri.monitor_set.switch_workspace_up();
|
self.niri.layout.switch_workspace_up();
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::FocusWorkspace(idx) => {
|
Action::FocusWorkspace(idx) => {
|
||||||
self.niri.monitor_set.switch_workspace(idx);
|
self.niri.layout.switch_workspace(idx);
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::ConsumeWindowIntoColumn => {
|
Action::ConsumeWindowIntoColumn => {
|
||||||
self.niri.monitor_set.consume_into_column();
|
self.niri.layout.consume_into_column();
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::ExpelWindowFromColumn => {
|
Action::ExpelWindowFromColumn => {
|
||||||
self.niri.monitor_set.expel_from_column();
|
self.niri.layout.expel_from_column();
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::SwitchPresetColumnWidth => {
|
Action::SwitchPresetColumnWidth => {
|
||||||
self.niri.monitor_set.toggle_width();
|
self.niri.layout.toggle_width();
|
||||||
}
|
}
|
||||||
Action::MaximizeColumn => {
|
Action::MaximizeColumn => {
|
||||||
self.niri.monitor_set.toggle_full_width();
|
self.niri.layout.toggle_full_width();
|
||||||
}
|
}
|
||||||
Action::FocusMonitorLeft => {
|
Action::FocusMonitorLeft => {
|
||||||
if let Some(output) = self.niri.output_left() {
|
if let Some(output) = self.niri.output_left() {
|
||||||
self.niri.monitor_set.focus_output(&output);
|
self.niri.layout.focus_output(&output);
|
||||||
self.move_cursor_to_output(&output);
|
self.move_cursor_to_output(&output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::FocusMonitorRight => {
|
Action::FocusMonitorRight => {
|
||||||
if let Some(output) = self.niri.output_right() {
|
if let Some(output) = self.niri.output_right() {
|
||||||
self.niri.monitor_set.focus_output(&output);
|
self.niri.layout.focus_output(&output);
|
||||||
self.move_cursor_to_output(&output);
|
self.move_cursor_to_output(&output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::FocusMonitorDown => {
|
Action::FocusMonitorDown => {
|
||||||
if let Some(output) = self.niri.output_down() {
|
if let Some(output) = self.niri.output_down() {
|
||||||
self.niri.monitor_set.focus_output(&output);
|
self.niri.layout.focus_output(&output);
|
||||||
self.move_cursor_to_output(&output);
|
self.move_cursor_to_output(&output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::FocusMonitorUp => {
|
Action::FocusMonitorUp => {
|
||||||
if let Some(output) = self.niri.output_up() {
|
if let Some(output) = self.niri.output_up() {
|
||||||
self.niri.monitor_set.focus_output(&output);
|
self.niri.layout.focus_output(&output);
|
||||||
self.move_cursor_to_output(&output);
|
self.move_cursor_to_output(&output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::MoveWindowToMonitorLeft => {
|
Action::MoveWindowToMonitorLeft => {
|
||||||
if let Some(output) = self.niri.output_left() {
|
if let Some(output) = self.niri.output_left() {
|
||||||
self.niri.monitor_set.move_to_output(&output);
|
self.niri.layout.move_to_output(&output);
|
||||||
self.move_cursor_to_output(&output);
|
self.move_cursor_to_output(&output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::MoveWindowToMonitorRight => {
|
Action::MoveWindowToMonitorRight => {
|
||||||
if let Some(output) = self.niri.output_right() {
|
if let Some(output) = self.niri.output_right() {
|
||||||
self.niri.monitor_set.move_to_output(&output);
|
self.niri.layout.move_to_output(&output);
|
||||||
self.move_cursor_to_output(&output);
|
self.move_cursor_to_output(&output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::MoveWindowToMonitorDown => {
|
Action::MoveWindowToMonitorDown => {
|
||||||
if let Some(output) = self.niri.output_down() {
|
if let Some(output) = self.niri.output_down() {
|
||||||
self.niri.monitor_set.move_to_output(&output);
|
self.niri.layout.move_to_output(&output);
|
||||||
self.move_cursor_to_output(&output);
|
self.move_cursor_to_output(&output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::MoveWindowToMonitorUp => {
|
Action::MoveWindowToMonitorUp => {
|
||||||
if let Some(output) = self.niri.output_up() {
|
if let Some(output) = self.niri.output_up() {
|
||||||
self.niri.monitor_set.move_to_output(&output);
|
self.niri.layout.move_to_output(&output);
|
||||||
self.move_cursor_to_output(&output);
|
self.move_cursor_to_output(&output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::SetColumnWidth(change) => {
|
Action::SetColumnWidth(change) => {
|
||||||
self.niri.monitor_set.set_column_width(change);
|
self.niri.layout.set_column_width(change);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,9 +413,9 @@ impl State {
|
|||||||
if ButtonState::Pressed == button_state && !pointer.is_grabbed() {
|
if ButtonState::Pressed == button_state && !pointer.is_grabbed() {
|
||||||
if let Some(window) = self.niri.window_under_cursor() {
|
if let Some(window) = self.niri.window_under_cursor() {
|
||||||
let window = window.clone();
|
let window = window.clone();
|
||||||
self.niri.monitor_set.activate_window(&window);
|
self.niri.layout.activate_window(&window);
|
||||||
} else if let Some(output) = self.niri.output_under_cursor() {
|
} else if let Some(output) = self.niri.output_under_cursor() {
|
||||||
self.niri.monitor_set.activate_output(&output);
|
self.niri.layout.activate_output(&output);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -546,9 +544,9 @@ impl State {
|
|||||||
if !pointer.is_grabbed() {
|
if !pointer.is_grabbed() {
|
||||||
if let Some(window) = self.niri.window_under_cursor() {
|
if let Some(window) = self.niri.window_under_cursor() {
|
||||||
let window = window.clone();
|
let window = window.clone();
|
||||||
self.niri.monitor_set.activate_window(&window);
|
self.niri.layout.activate_window(&window);
|
||||||
} else if let Some(output) = self.niri.output_under_cursor() {
|
} else if let Some(output) = self.niri.output_under_cursor() {
|
||||||
self.niri.monitor_set.activate_output(&output);
|
self.niri.layout.activate_output(&output);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+304
-152
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -115,7 +115,7 @@ fn main() {
|
|||||||
let _span = tracy_client::span!("loop callback");
|
let _span = tracy_client::span!("loop callback");
|
||||||
|
|
||||||
// These should be called periodically, before flushing the clients.
|
// These should be called periodically, before flushing the clients.
|
||||||
state.niri.monitor_set.refresh();
|
state.niri.layout.refresh();
|
||||||
state.niri.refresh_pointer_outputs();
|
state.niri.refresh_pointer_outputs();
|
||||||
state.niri.popups.cleanup();
|
state.niri.popups.cleanup();
|
||||||
state.update_focus();
|
state.update_focus();
|
||||||
|
|||||||
+25
-22
@@ -82,7 +82,7 @@ use crate::dbus::mutter_display_config::DisplayConfig;
|
|||||||
use crate::dbus::mutter_screen_cast::{self, ScreenCast, ToNiriMsg};
|
use crate::dbus::mutter_screen_cast::{self, ScreenCast, ToNiriMsg};
|
||||||
use crate::dbus::mutter_service_channel::ServiceChannel;
|
use crate::dbus::mutter_service_channel::ServiceChannel;
|
||||||
use crate::frame_clock::FrameClock;
|
use crate::frame_clock::FrameClock;
|
||||||
use crate::layout::{output_size, MonitorRenderElement, MonitorSet};
|
use crate::layout::{output_size, Layout, MonitorRenderElement};
|
||||||
use crate::pw_utils::{Cast, PipeWire};
|
use crate::pw_utils::{Cast, PipeWire};
|
||||||
use crate::utils::{center, get_monotonic_time, make_screenshot_path};
|
use crate::utils::{center, get_monotonic_time, make_screenshot_path};
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ pub struct Niri {
|
|||||||
|
|
||||||
// Each workspace corresponds to a Space. Each workspace generally has one Output mapped to it,
|
// Each workspace corresponds to a Space. Each workspace generally has one Output mapped to it,
|
||||||
// however it may have none (when there are no outputs connected) or mutiple (when mirroring).
|
// however it may have none (when there are no outputs connected) or mutiple (when mirroring).
|
||||||
pub monitor_set: MonitorSet<Window>,
|
pub layout: Layout<Window>,
|
||||||
|
|
||||||
// This space does not actually contain any windows, but all outputs are mapped into it
|
// This space does not actually contain any windows, but all outputs are mapped into it
|
||||||
// according to their global position.
|
// according to their global position.
|
||||||
@@ -245,7 +245,7 @@ impl State {
|
|||||||
pub fn update_focus(&mut self) {
|
pub fn update_focus(&mut self) {
|
||||||
let focus = self.niri.layer_surface_focus().or_else(|| {
|
let focus = self.niri.layer_surface_focus().or_else(|| {
|
||||||
self.niri
|
self.niri
|
||||||
.monitor_set
|
.layout
|
||||||
.focus()
|
.focus()
|
||||||
.map(|win| win.toplevel().wl_surface().clone())
|
.map(|win| win.toplevel().wl_surface().clone())
|
||||||
});
|
});
|
||||||
@@ -268,6 +268,8 @@ impl State {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.niri.layout.update_config(&config);
|
||||||
|
|
||||||
let mut old_config = self.niri.config.borrow_mut();
|
let mut old_config = self.niri.config.borrow_mut();
|
||||||
|
|
||||||
if config.cursor != old_config.cursor {
|
if config.cursor != old_config.cursor {
|
||||||
@@ -299,6 +301,8 @@ impl Niri {
|
|||||||
let display_handle = display.handle();
|
let display_handle = display.handle();
|
||||||
let config_ = config.borrow();
|
let config_ = config.borrow();
|
||||||
|
|
||||||
|
let layout = Layout::new(&config_);
|
||||||
|
|
||||||
let compositor_state = CompositorState::new::<State>(&display_handle);
|
let compositor_state = CompositorState::new::<State>(&display_handle);
|
||||||
let xdg_shell_state = XdgShellState::new_with_capabilities::<State>(
|
let xdg_shell_state = XdgShellState::new_with_capabilities::<State>(
|
||||||
&display_handle,
|
&display_handle,
|
||||||
@@ -677,7 +681,7 @@ impl Niri {
|
|||||||
stop_signal,
|
stop_signal,
|
||||||
display_handle,
|
display_handle,
|
||||||
|
|
||||||
monitor_set: MonitorSet::new(),
|
layout,
|
||||||
global_space: Space::default(),
|
global_space: Space::default(),
|
||||||
output_state: HashMap::new(),
|
output_state: HashMap::new(),
|
||||||
output_by_name: HashMap::new(),
|
output_by_name: HashMap::new(),
|
||||||
@@ -780,7 +784,7 @@ impl Niri {
|
|||||||
position.x, position.y
|
position.x, position.y
|
||||||
);
|
);
|
||||||
self.global_space.map_output(&output, position);
|
self.global_space.map_output(&output, position);
|
||||||
self.monitor_set.add_output(output.clone());
|
self.layout.add_output(output.clone());
|
||||||
|
|
||||||
let state = OutputState {
|
let state = OutputState {
|
||||||
global,
|
global,
|
||||||
@@ -796,7 +800,7 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_output(&mut self, output: &Output) {
|
pub fn remove_output(&mut self, output: &Output) {
|
||||||
self.monitor_set.remove_output(output);
|
self.layout.remove_output(output);
|
||||||
self.global_space.unmap_output(output);
|
self.global_space.unmap_output(output);
|
||||||
// FIXME: reposition outputs so they are adjacent.
|
// FIXME: reposition outputs so they are adjacent.
|
||||||
|
|
||||||
@@ -834,7 +838,7 @@ impl Niri {
|
|||||||
|
|
||||||
pub fn output_resized(&mut self, output: Output) {
|
pub fn output_resized(&mut self, output: Output) {
|
||||||
layer_map_for_output(&output).arrange();
|
layer_map_for_output(&output).arrange();
|
||||||
self.monitor_set.update_output_size(&output);
|
self.layout.update_output_size(&output);
|
||||||
self.queue_redraw(output);
|
self.queue_redraw(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,7 +858,7 @@ impl Niri {
|
|||||||
pub fn window_under_cursor(&self) -> Option<&Window> {
|
pub fn window_under_cursor(&self) -> Option<&Window> {
|
||||||
let pos = self.seat.get_pointer().unwrap().current_location();
|
let pos = self.seat.get_pointer().unwrap().current_location();
|
||||||
let (output, pos_within_output) = self.output_under(pos)?;
|
let (output, pos_within_output) = self.output_under(pos)?;
|
||||||
let (window, _loc) = self.monitor_set.window_under(output, pos_within_output)?;
|
let (window, _loc) = self.layout.window_under(output, pos_within_output)?;
|
||||||
Some(window)
|
Some(window)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,7 +873,7 @@ impl Niri {
|
|||||||
) -> Option<(WlSurface, Point<i32, Logical>)> {
|
) -> Option<(WlSurface, Point<i32, Logical>)> {
|
||||||
let (output, pos_within_output) = self.output_under(pos)?;
|
let (output, pos_within_output) = self.output_under(pos)?;
|
||||||
let (window, win_pos_within_output) =
|
let (window, win_pos_within_output) =
|
||||||
self.monitor_set.window_under(output, pos_within_output)?;
|
self.layout.window_under(output, pos_within_output)?;
|
||||||
|
|
||||||
let (surface, surface_pos_within_output) = window
|
let (surface, surface_pos_within_output) = window
|
||||||
.surface_under(
|
.surface_under(
|
||||||
@@ -889,7 +893,7 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn output_left(&self) -> Option<Output> {
|
pub fn output_left(&self) -> Option<Output> {
|
||||||
let active = self.monitor_set.active_output()?;
|
let active = self.layout.active_output()?;
|
||||||
let active_geo = self.global_space.output_geometry(active).unwrap();
|
let active_geo = self.global_space.output_geometry(active).unwrap();
|
||||||
let extended_geo = Rectangle::from_loc_and_size(
|
let extended_geo = Rectangle::from_loc_and_size(
|
||||||
(i32::MIN / 2, active_geo.loc.y),
|
(i32::MIN / 2, active_geo.loc.y),
|
||||||
@@ -906,7 +910,7 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn output_right(&self) -> Option<Output> {
|
pub fn output_right(&self) -> Option<Output> {
|
||||||
let active = self.monitor_set.active_output()?;
|
let active = self.layout.active_output()?;
|
||||||
let active_geo = self.global_space.output_geometry(active).unwrap();
|
let active_geo = self.global_space.output_geometry(active).unwrap();
|
||||||
let extended_geo = Rectangle::from_loc_and_size(
|
let extended_geo = Rectangle::from_loc_and_size(
|
||||||
(i32::MIN / 2, active_geo.loc.y),
|
(i32::MIN / 2, active_geo.loc.y),
|
||||||
@@ -923,7 +927,7 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn output_up(&self) -> Option<Output> {
|
pub fn output_up(&self) -> Option<Output> {
|
||||||
let active = self.monitor_set.active_output()?;
|
let active = self.layout.active_output()?;
|
||||||
let active_geo = self.global_space.output_geometry(active).unwrap();
|
let active_geo = self.global_space.output_geometry(active).unwrap();
|
||||||
let extended_geo = Rectangle::from_loc_and_size(
|
let extended_geo = Rectangle::from_loc_and_size(
|
||||||
(active_geo.loc.x, i32::MIN / 2),
|
(active_geo.loc.x, i32::MIN / 2),
|
||||||
@@ -940,7 +944,7 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn output_down(&self) -> Option<Output> {
|
pub fn output_down(&self) -> Option<Output> {
|
||||||
let active = self.monitor_set.active_output()?;
|
let active = self.layout.active_output()?;
|
||||||
let active_geo = self.global_space.output_geometry(active).unwrap();
|
let active_geo = self.global_space.output_geometry(active).unwrap();
|
||||||
let extended_geo = Rectangle::from_loc_and_size(
|
let extended_geo = Rectangle::from_loc_and_size(
|
||||||
(active_geo.loc.x, i32::MIN / 2),
|
(active_geo.loc.x, i32::MIN / 2),
|
||||||
@@ -965,7 +969,7 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn layer_surface_focus(&self) -> Option<WlSurface> {
|
fn layer_surface_focus(&self) -> Option<WlSurface> {
|
||||||
let output = self.monitor_set.active_output()?;
|
let output = self.layout.active_output()?;
|
||||||
let layers = layer_map_for_output(output);
|
let layers = layer_map_for_output(output);
|
||||||
let surface = layers
|
let surface = layers
|
||||||
.layers_on(Layer::Overlay)
|
.layers_on(Layer::Overlay)
|
||||||
@@ -1177,7 +1181,7 @@ impl Niri {
|
|||||||
let output_scale = Scale::from(output.current_scale().fractional_scale());
|
let output_scale = Scale::from(output.current_scale().fractional_scale());
|
||||||
|
|
||||||
// Get monitor elements.
|
// Get monitor elements.
|
||||||
let mon = self.monitor_set.monitor_for_output(output).unwrap();
|
let mon = self.layout.monitor_for_output(output).unwrap();
|
||||||
let monitor_elements = mon.render_elements(renderer);
|
let monitor_elements = mon.render_elements(renderer);
|
||||||
|
|
||||||
// The pointer goes on the top.
|
// The pointer goes on the top.
|
||||||
@@ -1246,10 +1250,9 @@ impl Niri {
|
|||||||
let presentation_time = state.frame_clock.next_presentation_time();
|
let presentation_time = state.frame_clock.next_presentation_time();
|
||||||
|
|
||||||
// Update from the config and advance the animations.
|
// Update from the config and advance the animations.
|
||||||
self.monitor_set.update_config(&self.config.borrow());
|
self.layout.advance_animations(presentation_time);
|
||||||
self.monitor_set.advance_animations(presentation_time);
|
|
||||||
state.unfinished_animations_remain = self
|
state.unfinished_animations_remain = self
|
||||||
.monitor_set
|
.layout
|
||||||
.monitor_for_output(output)
|
.monitor_for_output(output)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.are_animations_ongoing();
|
.are_animations_ongoing();
|
||||||
@@ -1341,7 +1344,7 @@ impl Niri {
|
|||||||
// The reason to do this at all is that it keeps track of whether the surface is visible or
|
// The reason to do this at all is that it keeps track of whether the surface is visible or
|
||||||
// not in a unified way with the pointer surfaces, which makes the logic elsewhere simpler.
|
// not in a unified way with the pointer surfaces, which makes the logic elsewhere simpler.
|
||||||
|
|
||||||
for win in self.monitor_set.windows_for_output(output) {
|
for win in self.layout.windows_for_output(output) {
|
||||||
win.with_surfaces(|surface, states| {
|
win.with_surfaces(|surface, states| {
|
||||||
update_surface_primary_scanout_output(
|
update_surface_primary_scanout_output(
|
||||||
surface,
|
surface,
|
||||||
@@ -1374,7 +1377,7 @@ impl Niri {
|
|||||||
// We can unconditionally send the current output's feedback to regular and layer-shell
|
// We can unconditionally send the current output's feedback to regular and layer-shell
|
||||||
// surfaces, as they can only be displayed on a single output at a time. Even if a surface
|
// surfaces, as they can only be displayed on a single output at a time. Even if a surface
|
||||||
// is currently invisible, this is the DMABUF feedback that it should know about.
|
// is currently invisible, this is the DMABUF feedback that it should know about.
|
||||||
for win in self.monitor_set.windows_for_output(output) {
|
for win in self.layout.windows_for_output(output) {
|
||||||
win.send_dmabuf_feedback(output, |_, _| Some(output.clone()), |_, _| feedback);
|
win.send_dmabuf_feedback(output, |_, _| Some(output.clone()), |_, _| feedback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1445,7 +1448,7 @@ impl Niri {
|
|||||||
|
|
||||||
let frame_callback_time = get_monotonic_time();
|
let frame_callback_time = get_monotonic_time();
|
||||||
|
|
||||||
for win in self.monitor_set.windows_for_output(output) {
|
for win in self.layout.windows_for_output(output) {
|
||||||
win.send_frame(output, frame_callback_time, None, should_send);
|
win.send_frame(output, frame_callback_time, None, should_send);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1491,7 +1494,7 @@ impl Niri {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for win in self.monitor_set.windows_for_output(output) {
|
for win in self.layout.windows_for_output(output) {
|
||||||
win.take_presentation_feedback(
|
win.take_presentation_feedback(
|
||||||
&mut feedback,
|
&mut feedback,
|
||||||
surface_primary_scanout_output,
|
surface_primary_scanout_output,
|
||||||
|
|||||||
Reference in New Issue
Block a user