Skip to content

Commit

Permalink
Add a full set of external commands to control LeftWM
Browse files Browse the repository at this point in the history
  • Loading branch information
lex148 committed May 26, 2020
1 parent ee5c8dd commit 3d4173d
Show file tree
Hide file tree
Showing 14 changed files with 210 additions and 34 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG
Expand Up @@ -4,7 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [Unreleased 0.2.4]
### Fixed
### Added
- New Layouts

## [0.2.3] - 2020-5-15
### Fixed
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "leftwm"
version = "0.2.3"
version = "0.2.4"
authors = ["Lex Childs <lexchilds@gmail.com>"]
description = "A window manager for Adventurers"
edition = "2018"
Expand Down
2 changes: 1 addition & 1 deletion src/bin/leftwm-state.rs
Expand Up @@ -10,7 +10,7 @@ use xdg::BaseDirectories;
fn main() -> Result<()> {
let matches = App::new("LeftWM State")
.author("Lex Childs <lex.childs@gmail.com>")
.version("0.2.3")
.version("0.2.4")
.about("prints out the current state of LeftWM")
.arg(
Arg::with_name("template")
Expand Down
14 changes: 14 additions & 0 deletions src/config.rs
Expand Up @@ -24,6 +24,7 @@ pub struct Config {
pub modkey: String,
pub workspaces: Option<Vec<WorkspaceConfig>>,
pub tags: Option<Vec<String>>,
//pub layouts: Option<Vec<String>>,
pub keybind: Vec<Keybind>,
}

Expand Down Expand Up @@ -246,9 +247,22 @@ impl Default for Config {
.map(|s| s.to_string())
.collect();

//let layouts = vec![
// "MainAndVertStack",
// "GridHorizontal",
// "EvenHorizontal",
// "EvenVertical",
// "Fibonacci",
// "CenterMain",
//]
//.iter()
//.map(|s| s.to_string())
//.collect();

Config {
workspaces: Some(vec![]),
tags: Some(tags),
//layouts: Some(layouts),
modkey: "Mod4".to_owned(), //win key
keybind: commands,
}
Expand Down
4 changes: 1 addition & 3 deletions src/handlers/command_handler.rs
@@ -1,6 +1,5 @@
use super::*;
use crate::display_action::DisplayAction;
use crate::state;
use crate::utils::helpers;

pub fn process(manager: &mut Manager, command: Command, val: Option<String>) -> bool {
Expand Down Expand Up @@ -272,8 +271,7 @@ pub fn process(manager: &mut Manager, command: Command, val: Option<String>) ->
Command::SoftReload => {
manager.soft_reload();
false

},
}
Command::HardReload => {
manager.hard_reload();
false
Expand Down
50 changes: 49 additions & 1 deletion src/handlers/external_command_handler.rs
@@ -1,8 +1,8 @@
use super::*;
use crate::command::Command;
use crate::config::ThemeSetting;
use crate::utils::command_pipe::ExternalCommand;
use crate::utils::window_updater::update_windows;

pub fn process(manager: &mut Manager, command: ExternalCommand) -> bool {
let needs_redraw = process_work(manager, command);
if needs_redraw {
Expand Down Expand Up @@ -40,6 +40,54 @@ fn process_work(manager: &mut Manager, command: ExternalCommand) -> bool {
}
}

ExternalCommand::SendWindowToTag(tag_index) => {
if tag_index < manager.tags.len() {
//tag number as 1 based.
let tag_num = format!("{}", tag_index + 1);
return command_handler::process(manager, Command::MoveToTag, Some(tag_num));
}
}

ExternalCommand::SwapScreens => {
return command_handler::process(manager, Command::SwapTags, None);
}

ExternalCommand::MoveWindowToLastWorkspace => {
return command_handler::process(manager, Command::MoveToLastWorkspace, None);
}

ExternalCommand::MoveWindowUp => {
return command_handler::process(manager, Command::MoveWindowUp, None);
}
ExternalCommand::MoveWindowDown => {
return command_handler::process(manager, Command::MoveWindowDown, None);
}

ExternalCommand::FocusWindowUp => {
return command_handler::process(manager, Command::FocusWindowUp, None);
}
ExternalCommand::FocusWindowDown => {
return command_handler::process(manager, Command::FocusWindowDown, None);
}

ExternalCommand::FocusWorkspaceNext => {
return command_handler::process(manager, Command::FocusWorkspaceNext, None);
}
ExternalCommand::FocusWorkspacePrevious => {
return command_handler::process(manager, Command::FocusWorkspacePrevious, None);
}

ExternalCommand::NextLayout => {
return command_handler::process(manager, Command::NextLayout, None);
}
ExternalCommand::PreviousLayout => {
return command_handler::process(manager, Command::PreviousLayout, None);
}

ExternalCommand::CloseWindow => {
return command_handler::process(manager, Command::CloseWindow, None);
}

_ => {}
}

Expand Down
70 changes: 48 additions & 22 deletions src/layouts/mod.rs
Expand Up @@ -9,7 +9,7 @@ mod fibonacci;
mod grid_horizontal;
mod main_and_vert_stack;

#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub enum Layout {
MainAndVertStack,
GridHorizontal,
Expand All @@ -21,34 +21,36 @@ pub enum Layout {

impl Default for Layout {
fn default() -> Self {
Self::MainAndVertStack
let layouts: Vec<Layout> = LAYOUTS.iter().map(|&x| x.into()).collect();
layouts.first().unwrap().clone()
}
}

// This is tedious, but simple and effective.
impl Layout {
pub fn next_layout(&self) -> Self {
match self {
Self::MainAndVertStack => Self::GridHorizontal,
Self::GridHorizontal => Self::EvenHorizontal,
Self::EvenHorizontal => Self::EvenVertical,
Self::EvenVertical => Self::Fibonacci,
Self::Fibonacci => Self::CenterMain,
Self::CenterMain => Self::MainAndVertStack,
}
}
const LAYOUTS: &'static [&'static str] = &[
"MainAndVertStack",
"GridHorizontal",
"EvenHorizontal",
"EvenVertical",
"Fibonacci",
"CenterMain",
];

pub fn prev_layout(&self) -> Self {
match self {
Self::MainAndVertStack => Self::CenterMain,
Self::GridHorizontal => Self::MainAndVertStack,
Self::EvenHorizontal => Self::GridHorizontal,
Self::EvenVertical => Self::EvenHorizontal,
Self::Fibonacci => Self::EvenVertical,
Self::CenterMain => Self::Fibonacci,
impl From<&str> for Layout {
fn from(s: &str) -> Self {
match s {
"MainAndVertStack" => Self::MainAndVertStack,
"GridHorizontal" => Self::GridHorizontal,
"EvenHorizontal" => Self::EvenHorizontal,
"EvenVertical" => Self::EvenVertical,
"Fibonacci" => Self::Fibonacci,
"CenterMain" => Self::CenterMain,
_ => Self::MainAndVertStack,
}
}
}

// This is tedious, but simple and effective.
impl Layout {
pub fn update_windows(&self, workspace: &Workspace, windows: &mut Vec<&mut &mut Window>) {
match self {
Self::MainAndVertStack => main_and_vert_stack::update(workspace, windows),
Expand All @@ -59,6 +61,30 @@ impl Layout {
Self::CenterMain => center_main::update(workspace, windows),
}
}

pub fn next_layout(&self) -> Self {
let layouts: Vec<Layout> = LAYOUTS.iter().map(|&x| x.into()).collect();
let mut index = match layouts.iter().position(|x| x == self) {
Some(x) => x as isize,
None => return "Fibonacci".into(),
} + 1;
if index >= layouts.len() as isize {
index = 0;
}
layouts[index as usize].clone()
}

pub fn prev_layout(&self) -> Self {
let layouts: Vec<Layout> = LAYOUTS.iter().map(|&x| x.into()).collect();
let mut index = match layouts.iter().position(|x| x == self) {
Some(x) => x as isize,
None => return "Fibonacci".into(),
} - 1;
if index < 0 {
index = layouts.len() as isize - 1;
}
layouts[index as usize].clone()
}
}

#[cfg(test)]
Expand Down
59 changes: 55 additions & 4 deletions src/utils/command_pipe.rs
Expand Up @@ -15,7 +15,6 @@ type ResultQueue = Result<Queue>;
pub struct CommandPipe {
queue: ResultQueue,
}

impl Default for CommandPipe {
fn default() -> Self {
Self::new()
Expand Down Expand Up @@ -90,10 +89,35 @@ fn parse_command(s: String) -> std::result::Result<ExternalCommand, ()> {
} else if s.starts_with("Reload") {
return Ok(ExternalCommand::Reload);
} else if s.starts_with("LoadTheme ") {
return build_load_theme(s.clone());
return build_load_theme(s);
} else if s.starts_with("SendWorkspaceToTag ") {
return build_goto_tag(s.clone());
return build_send_workspace_to_tag(s);
} else if s.starts_with("SendWindowToTag ") {
return build_send_window_to_tag(s);
} else if s.starts_with("SwapScreens") {
return Ok(ExternalCommand::SwapScreens);
} else if s.starts_with("MoveWindowToLastWorkspace") {
return Ok(ExternalCommand::MoveWindowToLastWorkspace);
} else if s.starts_with("MoveWindowUp") {
return Ok(ExternalCommand::MoveWindowUp);
} else if s.starts_with("MoveWindowDown") {
return Ok(ExternalCommand::MoveWindowDown);
} else if s.starts_with("FocusWindowUp") {
return Ok(ExternalCommand::FocusWindowUp);
} else if s.starts_with("FocusWindowDown") {
return Ok(ExternalCommand::FocusWindowDown);
} else if s.starts_with("FocusWorkspaceNext") {
return Ok(ExternalCommand::FocusWorkspaceNext);
} else if s.starts_with("FocusWorkspacePrevious") {
return Ok(ExternalCommand::FocusWorkspacePrevious);
} else if s.starts_with("NextLayout") {
return Ok(ExternalCommand::NextLayout);
} else if s.starts_with("PreviousLayout") {
return Ok(ExternalCommand::PreviousLayout);
} else if s.starts_with("CloseWindow") {
return Ok(ExternalCommand::CloseWindow);
}

Err(())
}

Expand All @@ -107,7 +131,22 @@ fn build_load_theme(mut raw: String) -> std::result::Result<ExternalCommand, ()>
}
}

fn build_goto_tag(mut raw: String) -> std::result::Result<ExternalCommand, ()> {
fn build_send_window_to_tag(mut raw: String) -> std::result::Result<ExternalCommand, ()> {
crop_head(&mut raw, "SendWindowToTag ");
let parts: Vec<&str> = raw.split(' ').collect();
if parts.len() != 1 {
return Err(());
}
let tag_index = match parts[0].parse::<usize>() {
Ok(x) => x,
Err(_) => {
return Err(());
}
};
Ok(ExternalCommand::SendWindowToTag(tag_index))
}

fn build_send_workspace_to_tag(mut raw: String) -> std::result::Result<ExternalCommand, ()> {
crop_head(&mut raw, "SendWorkspaceToTag ");
let parts: Vec<&str> = raw.split(' ').collect();
if parts.len() != 2 {
Expand Down Expand Up @@ -146,4 +185,16 @@ pub enum ExternalCommand {
UnloadTheme,
Reload,
SendWorkspaceToTag(usize, usize),
SendWindowToTag(usize),
SwapScreens,
MoveWindowToLastWorkspace,
MoveWindowUp,
MoveWindowDown,
FocusWindowUp,
FocusWindowDown,
FocusWorkspaceNext,
FocusWorkspacePrevious,
CloseWindow,
NextLayout,
PreviousLayout,
}
28 changes: 28 additions & 0 deletions themes/controlling_leftwm/README.md
@@ -0,0 +1,28 @@
# How to control LeftWM from an external proccess

LeftWM supports being controlled using EWMH calls and from an external pipe
file.

This folder has example of how to send command to LeftWM using its external pipe
file.

A full list of supported command can be found here:

LoadTheme PATH_TO_THEME
UnloadTheme
Reload
SendWorkspaceToTag INDEX_OF_WORKSPACE, INDEX_OF_TAG
SendWindowToTag INDEX_OF_TAG
SwapScreens
MoveWindowToLastWorkspace
MoveWindowUp
MoveWindowDown
FocusWindowUp
FocusWindowDown
FocusWorkspaceNext
FocusWorkspacePrevious
CloseWindow
NextLayout
PreviousLayout


2 changes: 2 additions & 0 deletions themes/controlling_leftwm/change_to_tag
@@ -0,0 +1,2 @@
#!/bin/bash
echo "SendWorkspaceToTag $1 $2" > $XDG_RUNTIME_DIR/leftwm/commands.pipe
2 changes: 2 additions & 0 deletions themes/controlling_leftwm/move_window_to_last_workspace
@@ -0,0 +1,2 @@
#!/bin/bash
echo "MoveWindowToLastWorkspace" > $XDG_RUNTIME_DIR/leftwm/commands.pipe
2 changes: 2 additions & 0 deletions themes/controlling_leftwm/move_window_to_tag
@@ -0,0 +1,2 @@
#!/bin/bash
echo "SendWindowToTag $1" > $XDG_RUNTIME_DIR/leftwm/commands.pipe
2 changes: 2 additions & 0 deletions themes/controlling_leftwm/swap_screens
@@ -0,0 +1,2 @@
#!/bin/bash
echo "SwapScreens" > $XDG_RUNTIME_DIR/leftwm/commands.pipe

0 comments on commit 3d4173d

Please sign in to comment.