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