Add hyprsome fork
This commit is contained in:
parent
933322768f
commit
dcd09dee2a
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/result
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "hyprsome"
|
||||||
|
description = "A small CLI apps that allows to make Hyprland's workspaces work like Awesome in multi-monitor setup"
|
||||||
|
license = "GPL-3.0"
|
||||||
|
version = "0.1.11"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = { version = "4.0.15", features = ["derive"] }
|
||||||
|
ipc-rpc = "1.2.2"
|
||||||
|
schemars = "0.8.11"
|
||||||
|
serde = "1.0.145"
|
||||||
|
serde_json = "1.0.86"
|
||||||
|
tokio = "1.21.2"
|
||||||
|
hyprland = "0.3.1"
|
|
@ -0,0 +1,16 @@
|
||||||
|
The GPLv3 License (GPLv3)
|
||||||
|
|
||||||
|
Copyright (c) 2022 Author
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Hyprsome
|
||||||
|
Hyprsome is a binary that interacts with Hyprland's Unix socket to make workspaces behave similarly to AwesomeWM in a multi-monitor setup.
|
||||||
|
|
||||||
|
If you're focused on a monitor and press SUPER+[1-9], you'll only switch to the workspaces that are bound to that monitor.
|
||||||
|
|
||||||
|
It is inspired by Swaysome, which does a similar thing for Sway.
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
`
|
||||||
|
cargo install hyprsome
|
||||||
|
`
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
Once the binary is installed, you can modify your ~/.config/hypr/hyprland.conf to accomodate it.
|
||||||
|
Here is an example of a dual monitor setup:
|
||||||
|
|
||||||
|
```
|
||||||
|
monitor=DP-1,1920x1080@60,0x0,1.33
|
||||||
|
monitor=DP-1,transform,1
|
||||||
|
workspace=DP-1,1
|
||||||
|
monitor=HDMI-A-1,3440x1440@100,813x0,1
|
||||||
|
workspace=HDMI-A-1,11
|
||||||
|
```
|
||||||
|
|
||||||
|
Most noteworthy thing here is the 'workspace' keyword that I use to bind a default workspace for each monitor.
|
||||||
|
|
||||||
|
|
||||||
|
Then you can bind workspaces to your different monitors.
|
||||||
|
|
||||||
|
It is very important that you bind your workspaces in order.
|
||||||
|
|
||||||
|
Check the results of `hyprctl monitors`. Bind workspaces from 1 to 9 on your monitor that has 0 as an id.
|
||||||
|
|
||||||
|
Then just bind workspaces by prefixing numbers by the id of the monitor they're bound to.
|
||||||
|
|
||||||
|
Here, HDMI-A-1's id is 1, so I bind workspaces from 11 to 19 to it.
|
||||||
|
|
||||||
|
```
|
||||||
|
workspace=1,monitor:DP-1
|
||||||
|
workspace=2,monitor:DP-1
|
||||||
|
workspace=3,monitor:DP-1
|
||||||
|
workspace=4,monitor:DP-1
|
||||||
|
workspace=5,monitor:DP-1
|
||||||
|
|
||||||
|
workspace=11,monitor:HDMI-A-1
|
||||||
|
workspace=12,monitor:HDMI-A-1
|
||||||
|
workspace=13,monitor:HDMI-A-1
|
||||||
|
workspace=14,monitor:HDMI-A-1
|
||||||
|
workspace=15,monitor:HDMI-A-1
|
||||||
|
```
|
||||||
|
|
||||||
|
Then it's just a matter of making sure your regular workspace keybinds call hyprsome.
|
||||||
|
|
||||||
|
```
|
||||||
|
bind=SUPER,1,exec,hyprsome workspace 1
|
||||||
|
bind=SUPER,2,exec,hyprsome workspace 2
|
||||||
|
bind=SUPER,3,exec,hyprsome workspace 3
|
||||||
|
bind=SUPER,4,exec,hyprsome workspace 4
|
||||||
|
bind=SUPER,5,exec,hyprsome workspace 5
|
||||||
|
|
||||||
|
bind=SUPERSHIFT,1,exec,hyprsome move 1
|
||||||
|
bind=SUPERSHIFT,2,exec,hyprsome move 2
|
||||||
|
bind=SUPERSHIFT,3,exec,hyprsome move 3
|
||||||
|
bind=SUPERSHIFT,4,exec,hyprsome move 4
|
||||||
|
bind=SUPERSHIFT,5,exec,hyprsome move 5
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
# Limitations
|
||||||
|
This is alpha software and my first program in Rust, bugs are bound to happen but nothing that will break your system.
|
||||||
|
|
||||||
|
Some features are most likely missing.
|
||||||
|
|
||||||
|
You can only have 9 workspaces per monitor as of now.
|
||||||
|
|
||||||
|
I haven't worked on supporting monitor hot-plug at all. It may work but it's unlikely.
|
|
@ -0,0 +1,159 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"crane": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1684981077,
|
||||||
|
"narHash": "sha256-68X9cFm0RTZm8u0rXPbeBzOVUH5OoUGAfeHHVoxGd9o=",
|
||||||
|
"owner": "ipetkov",
|
||||||
|
"repo": "crane",
|
||||||
|
"rev": "35110cccf28823320f4fd697fcafcb5038683982",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "ipetkov",
|
||||||
|
"repo": "crane",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1673956053,
|
||||||
|
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681202837,
|
||||||
|
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_2": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1685518550,
|
||||||
|
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1685498995,
|
||||||
|
"narHash": "sha256-rdyjnkq87tJp+T2Bm1OD/9NXKSsh/vLlPeqCc/mm7qs=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "9cfaa8a1a00830d17487cb60a19bb86f96f09b27",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"crane": "crane",
|
||||||
|
"flake-utils": "flake-utils_2",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": [
|
||||||
|
"crane",
|
||||||
|
"flake-utils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"crane",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1683080331,
|
||||||
|
"narHash": "sha256-nGDvJ1DAxZIwdn6ww8IFwzoHb2rqBP4wv/65Wt5vflk=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "d59c3fa0cba8336e115b376c2d9e91053aa59e56",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
|
crane.url = "github:ipetkov/crane";
|
||||||
|
crane.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, crane, flake-utils, ... }:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
craneLib = crane.lib.${system};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
packages.default = craneLib.buildPackage {
|
||||||
|
src = craneLib.cleanCargoSource (craneLib.path ./.);
|
||||||
|
# Add extra inputs here or any other derivation settings
|
||||||
|
# doCheck = true;
|
||||||
|
# buildInputs = [];
|
||||||
|
# nativeBuildInputs = [];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
use hyprland::{
|
||||||
|
data::{Client, Clients},
|
||||||
|
dispatch::{Direction, Dispatch, DispatchType},
|
||||||
|
shared::{HyprData, HyprDataActiveOptional},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn get_active() -> Option<Client> {
|
||||||
|
Client::get_active().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get() -> Clients {
|
||||||
|
Clients::get().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_by_direction(direction: Direction) {
|
||||||
|
let _ = Dispatch::call(DispatchType::MoveFocus(direction));
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
pub mod client;
|
||||||
|
pub mod monitor;
|
||||||
|
pub mod option;
|
||||||
|
pub mod workspace;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::os::unix::net::UnixStream;
|
||||||
|
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
fn send_message(action: &str, args: Vec<&str>) -> String {
|
||||||
|
let env_var_name = "HYPRLAND_INSTANCE_SIGNATURE";
|
||||||
|
|
||||||
|
let hyprland_instance_sig = match env::var(env_var_name) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => panic!("${} is not set ({})", env_var_name, e),
|
||||||
|
};
|
||||||
|
|
||||||
|
let socket_path = format!("/tmp/hypr/{}/.socket.sock", hyprland_instance_sig);
|
||||||
|
let mut stream = match UnixStream::connect(socket_path) {
|
||||||
|
Err(_) => panic!("server is not running"),
|
||||||
|
Ok(stream) => stream,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut message = format!("j/{}", action);
|
||||||
|
args.into_iter()
|
||||||
|
.for_each(|a| message.push_str(&format!(" {}", a)));
|
||||||
|
|
||||||
|
// TODO: stop being stinky and manage errors
|
||||||
|
let _ = stream.write_all(message.as_bytes());
|
||||||
|
let mut response = String::new();
|
||||||
|
|
||||||
|
// TODO: stop being stinky and manage errors
|
||||||
|
let _ = stream.read_to_string(&mut response);
|
||||||
|
response
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
use hyprland::data::{Monitor, Monitors};
|
||||||
|
use hyprland::dispatch::*;
|
||||||
|
use hyprland::shared::HyprData;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ActiveWorkspace {
|
||||||
|
pub id: u64,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_by_id(id: i16) -> Monitor {
|
||||||
|
let mut monitors = get();
|
||||||
|
monitors.find(|m| m.id == id).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get() -> Monitors {
|
||||||
|
Monitors::get().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_left() {
|
||||||
|
let _ = Dispatch::call(DispatchType::FocusMonitor(MonitorIdentifier::Direction(
|
||||||
|
Direction::Left,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_right() {
|
||||||
|
let _ = Dispatch::call(DispatchType::FocusMonitor(MonitorIdentifier::Direction(
|
||||||
|
Direction::Right,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_up() {
|
||||||
|
let _ = Dispatch::call(DispatchType::FocusMonitor(MonitorIdentifier::Direction(
|
||||||
|
Direction::Up,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_down() {
|
||||||
|
let _ = Dispatch::call(DispatchType::FocusMonitor(MonitorIdentifier::Direction(
|
||||||
|
Direction::Down,
|
||||||
|
)));
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
const GETOPTIONS: &str = "getoptions";
|
||||||
|
const GENERAL_GAPS_OUT: &str = "general:gaps_out";
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct HyprlandOption {
|
||||||
|
pub option: String,
|
||||||
|
pub int: i32,
|
||||||
|
pub float: f64,
|
||||||
|
pub str: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_gaps() -> i16 {
|
||||||
|
let response = super::send_message(GETOPTIONS, vec![GENERAL_GAPS_OUT]);
|
||||||
|
let gap_option: HyprlandOption = serde_json::from_str(&response).unwrap();
|
||||||
|
|
||||||
|
gap_option.int as i16
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
// TODO: change this file to hyprland-rs
|
||||||
|
const WORKSPACE: &str = "workspace";
|
||||||
|
const DISPATCH: &str = "dispatch";
|
||||||
|
const MOVETOWORKSPACESILENT: &str = "movetoworkspacesilent";
|
||||||
|
const MOVETOWORKSPACE: &str = "movetoworkspace";
|
||||||
|
|
||||||
|
pub fn focus(workspace_number: &u64) {
|
||||||
|
let _ = super::send_message(DISPATCH, vec![WORKSPACE, &workspace_number.to_string()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_to(workspace_number: &u64) {
|
||||||
|
super::send_message(
|
||||||
|
DISPATCH,
|
||||||
|
vec![MOVETOWORKSPACESILENT, &workspace_number.to_string()],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_focus(workspace_number: &u64) {
|
||||||
|
super::send_message(
|
||||||
|
DISPATCH,
|
||||||
|
vec![MOVETOWORKSPACE, &workspace_number.to_string()],
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,350 @@
|
||||||
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
|
|
||||||
|
mod hyprland_ipc;
|
||||||
|
use hyprland::{
|
||||||
|
data::{Client, Monitor, Transforms, Workspaces},
|
||||||
|
dispatch::Direction, shared::HyprData,
|
||||||
|
};
|
||||||
|
use hyprland_ipc::{client, monitor, option, workspace};
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(name = "hyprsome")]
|
||||||
|
#[command(author = "sopa0")]
|
||||||
|
#[command(version = "0.1.11")]
|
||||||
|
#[command(about = "Makes hyprland workspaces behave like awesome", long_about = None)]
|
||||||
|
struct Cli {
|
||||||
|
#[command(subcommand)]
|
||||||
|
command: Commands,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum Commands {
|
||||||
|
Focus { direction: Directions },
|
||||||
|
Workspace { workspace_number: u64 },
|
||||||
|
Move { workspace_number: u64 },
|
||||||
|
Movefocus { workspace_number: u64 },
|
||||||
|
MoveEmpty,
|
||||||
|
FocusEmpty,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)]
|
||||||
|
enum Directions {
|
||||||
|
L,
|
||||||
|
R,
|
||||||
|
U,
|
||||||
|
D,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MonitorDimensions {
|
||||||
|
fn real_width(&self) -> f32;
|
||||||
|
fn real_height(&self) -> f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MonitorDimensions for Monitor {
|
||||||
|
fn real_width(&self) -> f32 {
|
||||||
|
match self.transform {
|
||||||
|
Transforms::Normal
|
||||||
|
| Transforms::Normal180
|
||||||
|
| Transforms::Flipped
|
||||||
|
| Transforms::Flipped180 => self.width as f32 / self.scale,
|
||||||
|
Transforms::Normal90 | Transforms::Normal270 | Transforms::Flipped90 => {
|
||||||
|
self.height as f32 / self.scale
|
||||||
|
}
|
||||||
|
_ => self.width as f32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn real_height(&self) -> f32 {
|
||||||
|
match self.transform {
|
||||||
|
Transforms::Normal
|
||||||
|
| Transforms::Flipped
|
||||||
|
| Transforms::Normal180
|
||||||
|
| Transforms::Flipped180 => self.height as f32 / self.scale,
|
||||||
|
Transforms::Normal90 | Transforms::Normal270 | Transforms::Flipped90 => {
|
||||||
|
self.width as f32 / self.scale
|
||||||
|
}
|
||||||
|
_ => self.height as f32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_monitor() -> Monitor {
|
||||||
|
monitor::get().find(|m| m.focused).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: refactor this nonsense
|
||||||
|
pub fn select_workspace(workspace_number: &u64) {
|
||||||
|
let mon = get_current_monitor();
|
||||||
|
match mon.id {
|
||||||
|
0 => workspace::focus(workspace_number),
|
||||||
|
_ => {
|
||||||
|
workspace::focus(
|
||||||
|
&format!("{}{}", mon.id, workspace_number)
|
||||||
|
.parse::<u64>()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_empty_workspace() -> u64 {
|
||||||
|
let mon = get_current_monitor();
|
||||||
|
let mut found = Vec::new();
|
||||||
|
for workspaces in Workspaces::get().iter() {
|
||||||
|
for workspace in workspaces.iter() {
|
||||||
|
if workspace.monitor == mon.name {
|
||||||
|
let mut id = workspace.name.clone();
|
||||||
|
if id.len() > 1 {
|
||||||
|
id = id.chars().nth(1).unwrap().to_string();
|
||||||
|
}
|
||||||
|
found.push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i in 1..9 {
|
||||||
|
if !found.contains(&i.to_string()) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1; // Send to the first workspace if no others are available
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: refactor this nonsense
|
||||||
|
pub fn send_to_workspace(workspace_number: &u64) {
|
||||||
|
let mon = get_current_monitor();
|
||||||
|
match mon.id {
|
||||||
|
0 => workspace::move_to(workspace_number),
|
||||||
|
_ => {
|
||||||
|
workspace::move_to(
|
||||||
|
&format!("{}{}", mon.id, workspace_number)
|
||||||
|
.parse::<u64>()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: refactor this nonsense
|
||||||
|
pub fn movefocus(workspace_number: &u64) {
|
||||||
|
let mon = get_current_monitor();
|
||||||
|
match mon.id {
|
||||||
|
0 => workspace::move_focus(workspace_number),
|
||||||
|
_ => {
|
||||||
|
workspace::move_focus(
|
||||||
|
&format!("{}{}", mon.id, workspace_number)
|
||||||
|
.parse::<u64>()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_leftmost_client_for_monitor(mon_id: i16) -> Client {
|
||||||
|
let clients = client::get();
|
||||||
|
|
||||||
|
clients
|
||||||
|
.into_iter()
|
||||||
|
.filter(|c| c.monitor == mon_id)
|
||||||
|
.min_by_key(|c| c.at.0)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_left(aw: Client) {
|
||||||
|
let mon = monitor::get_by_id(aw.monitor);
|
||||||
|
let is_leftmost_client = is_leftmost_client(&aw, &mon);
|
||||||
|
|
||||||
|
if is_leftmost_monitor(&mon) && is_leftmost_client {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_leftmost_client {
|
||||||
|
monitor::focus_left();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client::focus_by_direction(Direction::Left);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_right(aw: Client) {
|
||||||
|
let mon = monitor::get_by_id(aw.monitor);
|
||||||
|
|
||||||
|
if is_rightmost_monitor(&mon) && is_rightmost_client(&aw, &mon) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_rightmost_client(&aw, &mon) {
|
||||||
|
monitor::focus_right();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client::focus_by_direction(Direction::Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_up(aw: Client) {
|
||||||
|
let mon = monitor::get_by_id(aw.monitor);
|
||||||
|
let is_top_client = is_top_client(&aw, &mon);
|
||||||
|
|
||||||
|
if is_top_monitor(&mon) && is_top_client {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_top_client {
|
||||||
|
monitor::focus_up();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client::focus_by_direction(Direction::Up);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_down(aw: Client) {
|
||||||
|
let mon = monitor::get_by_id(aw.monitor);
|
||||||
|
let is_bottom_client = is_bottom_client(&aw, &mon);
|
||||||
|
|
||||||
|
if is_bottom_monitor(&mon) && is_bottom_client {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_bottom_client {
|
||||||
|
monitor::focus_down();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client::focus_by_direction(Direction::Down);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_leftmost_client(aw: &Client, mon: &Monitor) -> bool {
|
||||||
|
let gaps = option::get_gaps();
|
||||||
|
|
||||||
|
if (aw.at.0 - gaps) as i32 == mon.x {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_rightmost_client(aw: &Client, mon: &Monitor) -> bool {
|
||||||
|
let gaps = option::get_gaps();
|
||||||
|
|
||||||
|
if mon.real_width() + mon.x as f32 - gaps as f32 == aw.size.0 as f32 + aw.at.0 as f32 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_top_client(aw: &Client, mon: &Monitor) -> bool {
|
||||||
|
let gaps = option::get_gaps();
|
||||||
|
|
||||||
|
if mon.y + (gaps as i32) + (mon.reserved.1 as i32) == (aw.at.1 as i32) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_bottom_client(aw: &Client, mon: &Monitor) -> bool {
|
||||||
|
let gaps = option::get_gaps();
|
||||||
|
|
||||||
|
if mon.real_height() + mon.y as f32 - gaps as f32 - mon.reserved.1 as f32
|
||||||
|
== aw.size.1 as f32 + gaps as f32
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_rightmost_monitor(mon: &Monitor) -> bool {
|
||||||
|
let monitors = monitor::get();
|
||||||
|
let max = monitors.into_iter().max_by_key(|m| m.x).unwrap();
|
||||||
|
if max.x == mon.x {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_leftmost_monitor(mon: &Monitor) -> bool {
|
||||||
|
let monitors = monitor::get();
|
||||||
|
let min = monitors.into_iter().min_by_key(|m| m.x).unwrap();
|
||||||
|
if min.x == mon.x {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_top_monitor(mon: &Monitor) -> bool {
|
||||||
|
let monitors = monitor::get();
|
||||||
|
let min = monitors.into_iter().min_by_key(|m| m.y).unwrap();
|
||||||
|
if min.y == mon.y {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_bottom_monitor(mon: &Monitor) -> bool {
|
||||||
|
let monitors = monitor::get();
|
||||||
|
let max = monitors.into_iter().max_by_key(|m| m.y).unwrap();
|
||||||
|
if max.y == mon.y {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
match &cli.command {
|
||||||
|
Commands::Focus { direction } => match direction {
|
||||||
|
Directions::L => {
|
||||||
|
let aw = client::get_active();
|
||||||
|
|
||||||
|
match aw {
|
||||||
|
Some(aw) => focus_left(aw),
|
||||||
|
None => monitor::focus_left(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Directions::R => {
|
||||||
|
let aw = client::get_active();
|
||||||
|
|
||||||
|
match aw {
|
||||||
|
Some(aw) => focus_right(aw),
|
||||||
|
None => monitor::focus_right(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Directions::U => {
|
||||||
|
let aw = client::get_active();
|
||||||
|
|
||||||
|
match aw {
|
||||||
|
Some(aw) => focus_up(aw),
|
||||||
|
None => monitor::focus_up(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Directions::D => {
|
||||||
|
let aw = client::get_active();
|
||||||
|
|
||||||
|
match aw {
|
||||||
|
Some(aw) => focus_down(aw),
|
||||||
|
None => monitor::focus_down(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Commands::Workspace { workspace_number } => {
|
||||||
|
select_workspace(workspace_number);
|
||||||
|
}
|
||||||
|
Commands::Move { workspace_number } => {
|
||||||
|
send_to_workspace(workspace_number);
|
||||||
|
}
|
||||||
|
Commands::Movefocus { workspace_number } => {
|
||||||
|
movefocus(workspace_number);
|
||||||
|
}
|
||||||
|
Commands::MoveEmpty => {
|
||||||
|
movefocus(&get_empty_workspace());
|
||||||
|
},
|
||||||
|
Commands::FocusEmpty => {
|
||||||
|
send_to_workspace(&get_empty_workspace());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue