#!/bin/bash # This script contains utility functions related to i3 workspaces. # Ensure required functions exist if ! command -v monitor_exist >/dev/null 2>&1; then echo "monitor_exist function is required but not found. Please source x.sh before i3.sh." 1>&2 exit 1 fi # Get the list of empty i3 workspaces. # Usage: get_empty_i3_workspaces get_empty_i3_workspaces() { set -euo pipefail i3-msg -t get_tree | jq -r ' recurse(.nodes[]?) | select(.type == "workspace") | select(.name | test("^[^_].*")) | select(.nodes | length == 0) | .name ' } # Check if the i3 workspace is empty. # Usage: i3_workspace_is_empty i3_workspace_is_empty() { set -euo pipefail local workspace_name=${1:?Workspace name not set} local empty_workspace empty_workspace=$(get_empty_i3_workspaces) for workspace in $empty_workspace; do if [ "$workspace" = "$workspace_name" ]; then return 0 fi done return 1 } # Get a comma separated list of i3 workspace names and the output they are on. # Usage: get_i3_workspaces get_i3_workspaces() { set -euo pipefail i3-msg -t get_workspaces | jq -r '.[] | .name + "," + .output' } # Get a property of an i3 workspace. # Usage: get_i3_workspace_prop get_i3_workspace_prop() { set -euo pipefail local workspace_name=${1:?Workspace name not set} local prop=${2:?Property not set} i3-msg -t get_workspaces | jq -r ".[] | select(.name == \"$workspace_name\") | .$prop" } # Check if an i3 workspace exists. # Usage: i3_workspace_exists i3_workspace_exists() { set -euo pipefail local workspace_name=${1:?Workspace name not set} if [[ -n "$(get_i3_workspace_prop "$workspace_name" name)" ]]; then return 0 fi return 1 } # Move an i3 workspace to a different monitor. # Usage: move_i3_workspace [increment] move_i3_workspace() { set -euo pipefail local workspace_name=${1:?Workspace name not set} local monitor_name=${2:?Monitor name not set} local increment=${3:-0} local new_workspace_name="$workspace_name" if ! i3_workspace_exists "$workspace_name"; then echo "Workspace $workspace_name not found" 1>&2 return 1 elif ! monitor_exist "$monitor_name"; then echo "Monitor $monitor_name not found" 1>&2 return 1 fi if [[ "$(get_i3_workspace_prop "$workspace_name" output)" == "$monitor_name" ]]; then echo "Workspace $workspace_name is already on monitor $monitor_name" 1>&2 return 1 fi if [[ "$workspace_name" =~ ^[0-9]+$ ]]; then new_workspace_name=$((workspace_name + increment)) elif [ "$increment" -ne 0 ]; then echo "Workspace name is not an integer. Unable to increment/decrement." 1>&2 return 1 fi if i3_workspace_exists "$new_workspace_name"; then if [[ "$new_workspace_name" != "$workspace_name" ]]; then echo "Workspace $new_workspace_name already exists" 1>&2 return 1 fi fi echo "Moving workspace $workspace_name to monitor $monitor_name as $new_workspace_name" i3-msg "workspace $workspace_name" 1>/dev/null i3-msg "rename workspace $workspace_name to $new_workspace_name" 1>/dev/null i3-msg "move workspace to output $monitor_name" 1>/dev/null } # Move all workspaces to a specified monitor. # Usage: move_nonexistent_i3_workspaces [increment] move_nonexistent_i3_workspaces() { set -euo pipefail local monitor_name=${1:?Monitor name not set} local increment=${2:-0} local workspaces workspaces=$(get_i3_workspaces) echo "Moving workspaces to monitor $monitor_name" for workspace in $workspaces; do local workspace_name local workspace_output workspace_name=$(echo "$workspace" | cut -d',' -f1) workspace_output=$(echo "$workspace" | cut -d',' -f2) if i3_workspace_is_empty "$workspace_name"; then echo "Skipping empty workspace $workspace_name" continue fi if ! monitor_exist "$workspace_output"; then move_i3_workspace "$workspace_name" "$monitor_name" "$increment" fi done }