Implemented some layouting commands

timeout_old
Tassilo Horn 3 years ago
parent 7471e66a72
commit 2210af2944
  1. 47
      Cargo.lock
  2. 2
      Cargo.toml
  3. 181
      src/cmds.rs
  4. 12
      src/con.rs
  5. 46
      src/layout.rs

47
Cargo.lock generated

@ -167,6 +167,12 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85"
[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]] [[package]]
name = "proc-macro-error" name = "proc-macro-error"
version = "1.0.4" version = "1.0.4"
@ -209,6 +215,46 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
dependencies = [
"rand_core",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.9" version = "0.2.9"
@ -317,6 +363,7 @@ dependencies = [
"clap", "clap",
"directories", "directories",
"lazy_static", "lazy_static",
"rand",
"regex", "regex",
"serde", "serde",
"serde_json", "serde_json",

@ -18,4 +18,4 @@ toml = "0.5.8"
directories = "3.0" directories = "3.0"
regex = "1.5.4" regex = "1.5.4"
lazy_static = "1.4.0" lazy_static = "1.4.0"
rand = "0.8.4"

@ -16,38 +16,73 @@
//! Functions and data structures of the swayr client. //! Functions and data structures of the swayr client.
use crate::con; use crate::con;
use crate::con::NodeMethods;
use crate::config as cfg; use crate::config as cfg;
use crate::layout;
use crate::util; use crate::util;
use crate::util::DisplayFormat; use crate::util::DisplayFormat;
use clap::Clap;
use rand;
use rand::prelude::SliceRandom;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::sync::RwLock; use std::sync::RwLock;
use swayipc as s; use swayipc as s;
use clap::Clap; #[derive(Clap, Debug, Deserialize, Serialize, PartialEq)]
pub enum ConsiderFloating {
/// Include floating windows.
IncludeFloating,
/// Exclude floating windows.
ExcludeFloating,
}
#[derive(Clap, Debug, Deserialize, Serialize)] #[derive(Clap, Debug, Deserialize, Serialize)]
pub enum SwayrCommand { pub enum SwayrCommand {
/// Switch to next urgent window (if any) or to last recently used window. /// Switch to next urgent window (if any) or to last recently used window.
SwitchToUrgentOrLRUWindow, SwitchToUrgentOrLRUWindow,
/// Focus the selected window /// Focus the selected window.
SwitchWindow, SwitchWindow,
/// Focus the next window. /// Focus the next window.
NextWindow, NextWindow,
/// Focus the previous window. /// Focus the previous window.
PrevWindow, PrevWindow,
/// Quit the selected window /// Quit the selected window.
QuitWindow, QuitWindow,
/// Switch to the selected workspace /// Switch to the selected workspace.
SwitchWorkspace, SwitchWorkspace,
/// Switch to the selected workspace or focus the selected window /// Switch to the selected workspace or focus the selected window.
SwitchWorkspaceOrWindow, SwitchWorkspaceOrWindow,
/// Quit all windows of selected workspace or the selected window /// Quit all windows of selected workspace or the selected window.
QuitWorkspaceOrWindow, QuitWorkspaceOrWindow,
/// Select and execute a swaymsg command /// Tab or shuffle-and-tile the windows on the current workspace, including
/// or excluding floating windows.
ToggleTabShuffleTileWorkspace {
#[clap(subcommand)]
floating: ConsiderFloating,
},
/// Tiles the windows on the current workspace, including or excluding
/// floating windows.
TileWorkspace {
#[clap(subcommand)]
floating: ConsiderFloating,
},
/// Tabs the windows on the current workspace, including or excluding
/// floating windows.
TabWorkspace {
#[clap(subcommand)]
floating: ConsiderFloating,
},
/// Shuffles and tiles the windows on the current workspace, including or
/// excluding floating windows.
ShuffleTileWorkspace {
#[clap(subcommand)]
floating: ConsiderFloating,
},
/// Select and execute a swaymsg command.
ExecuteSwaymsgCommand, ExecuteSwaymsgCommand,
/// Select and execute a swayr command /// Select and execute a swayr command.
ExecuteSwayrCommand, ExecuteSwayrCommand,
} }
@ -90,6 +125,24 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
SwayrCommand::QuitWorkspaceOrWindow => { SwayrCommand::QuitWorkspaceOrWindow => {
quit_workspace_or_window(Some(&*props.read().unwrap())) quit_workspace_or_window(Some(&*props.read().unwrap()))
} }
SwayrCommand::TileWorkspace { floating } => tile_current_workspace(
floating == &ConsiderFloating::IncludeFloating,
false,
),
SwayrCommand::TabWorkspace { floating } => tab_current_workspace(
floating == &ConsiderFloating::IncludeFloating,
),
SwayrCommand::ShuffleTileWorkspace { floating } => {
tile_current_workspace(
floating == &ConsiderFloating::IncludeFloating,
true,
)
}
SwayrCommand::ToggleTabShuffleTileWorkspace { floating } => {
toggle_tab_tile_current_workspace(
floating == &ConsiderFloating::IncludeFloating,
)
}
SwayrCommand::ExecuteSwaymsgCommand => exec_swaymsg_command(), SwayrCommand::ExecuteSwaymsgCommand => exec_swaymsg_command(),
SwayrCommand::ExecuteSwayrCommand => { SwayrCommand::ExecuteSwayrCommand => {
if let Some(c) = util::select_from_menu( if let Some(c) = util::select_from_menu(
@ -102,6 +155,30 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
SwayrCommand::SwitchWorkspace, SwayrCommand::SwitchWorkspace,
SwayrCommand::SwitchWorkspaceOrWindow, SwayrCommand::SwitchWorkspaceOrWindow,
SwayrCommand::SwitchToUrgentOrLRUWindow, SwayrCommand::SwitchToUrgentOrLRUWindow,
SwayrCommand::ToggleTabShuffleTileWorkspace {
floating: ConsiderFloating::ExcludeFloating,
},
SwayrCommand::ToggleTabShuffleTileWorkspace {
floating: ConsiderFloating::IncludeFloating,
},
SwayrCommand::TileWorkspace {
floating: ConsiderFloating::ExcludeFloating,
},
SwayrCommand::TileWorkspace {
floating: ConsiderFloating::IncludeFloating,
},
SwayrCommand::TabWorkspace {
floating: ConsiderFloating::ExcludeFloating,
},
SwayrCommand::TabWorkspace {
floating: ConsiderFloating::IncludeFloating,
},
SwayrCommand::ShuffleTileWorkspace {
floating: ConsiderFloating::ExcludeFloating,
},
SwayrCommand::ShuffleTileWorkspace {
floating: ConsiderFloating::IncludeFloating,
},
SwayrCommand::NextWindow, SwayrCommand::NextWindow,
SwayrCommand::PrevWindow, SwayrCommand::PrevWindow,
], ],
@ -258,6 +335,94 @@ pub fn quit_workspace_or_window(
} }
} }
fn tile_current_workspace(include_floating: bool, shuffle: bool) {
match layout::relayout_current_workspace(
include_floating,
Box::new(move |wins, con: &mut s::Connection| {
con.run_command("focus parent".to_string())?;
con.run_command("layout splith".to_string())?;
let mut placed_wins = vec![];
let mut rng = rand::thread_rng();
if shuffle {
wins.shuffle(&mut rng);
} else {
wins.reverse()
}
for win in wins {
std::thread::sleep(std::time::Duration::from_millis(25));
con.run_command(format!(
"[con_id={}] move to workspace current",
win.get_id()
))?;
std::thread::sleep(std::time::Duration::from_millis(25));
con.run_command(format!(
"[con_id={}] floating disable",
win.get_id()
))?;
placed_wins.push(win);
if shuffle {
std::thread::sleep(std::time::Duration::from_millis(25));
if let Some(win) = placed_wins.choose(&mut rng) {
con.run_command(format!(
"[con_id={}] focus",
win.get_id()
))?;
}
}
}
Ok(())
}),
) {
Ok(_) => (),
Err(err) => eprintln!("Error retiling workspace: {:?}", err),
}
}
fn tab_current_workspace(include_floating: bool) {
match layout::relayout_current_workspace(
include_floating,
Box::new(move |wins, con: &mut s::Connection| {
con.run_command("focus parent".to_string())?;
con.run_command("layout tabbed".to_string())?;
let mut placed_wins = vec![];
wins.reverse();
for win in wins {
std::thread::sleep(std::time::Duration::from_millis(25));
con.run_command(format!(
"[con_id={}] move to workspace current",
win.get_id()
))?;
std::thread::sleep(std::time::Duration::from_millis(25));
con.run_command(format!(
"[con_id={}] floating disable",
win.get_id()
))?;
placed_wins.push(win);
}
Ok(())
}),
) {
Ok(_) => (),
Err(err) => eprintln!("Error retiling workspace: {:?}", err),
}
}
fn toggle_tab_tile_current_workspace(include_floating: bool) {
let tree = get_tree();
let workspaces = tree.workspaces();
let cur_ws = workspaces
.iter()
.find(|w| con::is_current_container(w))
.unwrap();
if cur_ws.layout == s::NodeLayout::Tabbed {
tile_current_workspace(include_floating, true);
} else {
tab_current_workspace(include_floating);
}
}
fn get_swaymsg_commands<'a>() -> Vec<SwaymsgCmd<'a>> { fn get_swaymsg_commands<'a>() -> Vec<SwaymsgCmd<'a>> {
let mut cmds = vec![]; let mut cmds = vec![];

@ -153,6 +153,10 @@ impl Window<'_> {
pub fn is_focused(&self) -> bool { pub fn is_focused(&self) -> bool {
self.node.focused self.node.focused
} }
pub fn is_floating(&self) -> bool {
self.node.node_type == s::NodeType::FloatingCon
}
} }
impl PartialEq for Window<'_> { impl PartialEq for Window<'_> {
@ -433,6 +437,14 @@ impl Workspace<'_> {
pub fn is_scratchpad(&self) -> bool { pub fn is_scratchpad(&self) -> bool {
self.node.is_scratchpad() self.node.is_scratchpad()
} }
pub fn is_current(&self) -> bool {
is_current_container(self.node)
}
}
pub fn is_current_container(node: &s::Node) -> bool {
node.focused || NodeIter::new(node).any(|c| c.focused)
} }
impl PartialEq for Workspace<'_> { impl PartialEq for Workspace<'_> {

@ -15,6 +15,7 @@
//! Functions and data structures of the swayrd demon. //! Functions and data structures of the swayrd demon.
use crate::cmds;
use crate::con; use crate::con;
use crate::con::NodeMethods; use crate::con::NodeMethods;
use crate::config; use crate::config;
@ -123,3 +124,48 @@ pub fn maybe_auto_tile(config: &config::Config) {
println!("auto_tile: end\n"); println!("auto_tile: end\n");
} }
} }
pub fn relayout_current_workspace(
include_floating: bool,
insert_win_fn: Box<
dyn Fn(&mut [&con::Window], &mut s::Connection) -> s::Fallible<()>,
>,
) -> s::Fallible<()> {
let root = cmds::get_tree();
let workspaces = con::get_workspaces(&root, false, None);
if let Some(cur_ws) = workspaces.iter().find(|ws| ws.is_current()) {
if let Ok(mut con) = s::Connection::new() {
let mut moved_wins: Vec<&con::Window> = vec![];
let mut focused_win = None;
for win in &cur_ws.windows {
if win.is_focused() {
focused_win.insert(win);
}
if !include_floating && win.is_floating() {
continue;
}
moved_wins.push(win);
con.run_command(format!(
"[con_id={}] move to scratchpad",
win.get_id()
))?;
}
insert_win_fn(moved_wins.as_mut_slice(), &mut con)?;
std::thread::sleep(std::time::Duration::from_millis(25));
if let Some(win) = focused_win {
con.run_command(format!("[con_id={}] focus", win.get_id()))?;
}
Ok(())
} else {
Err(s::Error::CommandFailed(
"Cannot create connection.".to_string(),
))
}
} else {
Err(s::Error::CommandFailed(
"No workspace is focused.".to_string(),
))
}
}

Loading…
Cancel
Save