Add session manager for tmux.
This will open a tmux session for each monitor. Add helper script for tmux actions.
This commit is contained in:
34
i3/config
34
i3/config
@@ -34,10 +34,6 @@ exec --no-startup-id xss-lock --transfer-sleep-lock -- i3lock -f --nofork
|
||||
# and nm-applet is a desktop environment-independent system tray GUI for it.
|
||||
exec --no-startup-id nm-applet
|
||||
|
||||
# Wallpaper rotation script
|
||||
exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --once
|
||||
exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --daemon 1800
|
||||
|
||||
# Use pactl to adjust volume in PulseAudio.
|
||||
set $refresh_i3status killall -SIGUSR1 i3status
|
||||
bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10% && $refresh_i3status
|
||||
@@ -48,8 +44,15 @@ bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOU
|
||||
# Use Mouse+$mod to drag floating windows to their wanted position
|
||||
floating_modifier $mod
|
||||
|
||||
# start a terminal
|
||||
bindsym $mod+Return exec alacritty
|
||||
# start a terminal with smart monitor/workspace-aware tmux sessions
|
||||
bindsym $mod+Return exec --no-startup-id /home/jens/.config/i3/smart-terminal.sh
|
||||
|
||||
# fallback simple terminal (without smart sessions)
|
||||
bindsym $mod+Shift+Return exec --no-startup-id /home/jens/.config/i3/simple-terminal.sh
|
||||
|
||||
# tmux session management keybindings
|
||||
bindsym $mod+Shift+t exec --no-startup-id /home/jens/.cargo/bin/alacritty -e /home/jens/.config/i3/tmux-session-manager.sh
|
||||
bindsym $mod+Control+t exec --no-startup-id /home/jens/.config/i3/tmux-session-manager.sh list | rofi -dmenu -p "Tmux Sessions" -width 60
|
||||
|
||||
# kill focused window
|
||||
bindsym $mod+Shift+q kill
|
||||
@@ -63,6 +66,23 @@ bindsym $mod+Shift+q kill
|
||||
# bindcode $mod+40 exec --no-startup-id i3-dmenu-desktop
|
||||
bindsym $mod+d exec rofi -show run
|
||||
|
||||
# Screenshot bindings
|
||||
bindsym Print exec --no-startup-id ~/.local/bin/screenshot.sh full
|
||||
bindsym Shift+Print exec --no-startup-id ~/.local/bin/screenshot.sh selection
|
||||
bindsym $mod+Print exec --no-startup-id ~/.local/bin/screenshot.sh window
|
||||
bindsym Control+Print exec --no-startup-id ~/.local/bin/screenshot.sh clipboard
|
||||
bindsym Control+Shift+Print exec --no-startup-id ~/.local/bin/screenshot.sh clipboard-selection
|
||||
|
||||
# Alternative screenshot bindings for keyboards that send different codes
|
||||
bindsym XF86ScreenSaver exec --no-startup-id ~/.local/bin/screenshot.sh full
|
||||
bindsym Shift+XF86ScreenSaver exec --no-startup-id ~/.local/bin/screenshot.sh selection
|
||||
bindsym $mod+XF86ScreenSaver exec --no-startup-id ~/.local/bin/screenshot.sh window
|
||||
|
||||
# Additional screenshot bindings with mod+s combinations
|
||||
bindsym $mod+Shift+s exec --no-startup-id ~/.local/bin/screenshot.sh selection
|
||||
bindsym $mod+Control+s exec --no-startup-id ~/.local/bin/screenshot.sh window
|
||||
bindsym $mod+Control+Shift+s exec --no-startup-id ~/.local/bin/screenshot.sh full
|
||||
|
||||
# change focus
|
||||
bindsym $mod+j focus left
|
||||
bindsym $mod+k focus down
|
||||
@@ -116,7 +136,7 @@ bindsym $mod+a focus parent
|
||||
# Wallpaper controls
|
||||
bindsym $mod+Shift+w exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --once
|
||||
bindsym $mod+Shift+n exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --category nature
|
||||
bindsym $mod+Control+s exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --category space
|
||||
# bindsym $mod+Control+s exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --category space # Disabled - conflicts with screenshot binding
|
||||
bindsym $mod+Control+c exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --category cityscape
|
||||
|
||||
# Define names for default workspaces for which we configure key bindings later on.
|
||||
|
||||
13
i3/simple-terminal.sh
Executable file
13
i3/simple-terminal.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Simple fallback terminal launcher
|
||||
# Uses alacritty directly without complex session detection
|
||||
|
||||
ALACRITTY="/home/jens/.cargo/bin/alacritty"
|
||||
|
||||
if [ -x "$ALACRITTY" ]; then
|
||||
exec "$ALACRITTY"
|
||||
else
|
||||
# Fallback to xterm
|
||||
exec xterm
|
||||
fi
|
||||
97
i3/smart-terminal.sh
Executable file
97
i3/smart-terminal.sh
Executable file
@@ -0,0 +1,97 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Smart terminal launcher with monitor-aware tmux sessions
|
||||
# This script detects the current monitor and workspace to create/attach to appropriate tmux sessions
|
||||
|
||||
# Get the focused monitor using i3-msg
|
||||
get_current_monitor() {
|
||||
if command -v i3-msg &> /dev/null && i3-msg -t get_workspaces &>/dev/null; then
|
||||
i3-msg -t get_workspaces 2>/dev/null | jq -r '.[] | select(.focused==true) | .output' 2>/dev/null
|
||||
else
|
||||
echo "default"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get the current workspace number
|
||||
get_current_workspace() {
|
||||
if command -v i3-msg &> /dev/null && i3-msg -t get_workspaces &>/dev/null; then
|
||||
i3-msg -t get_workspaces 2>/dev/null | jq -r '.[] | select(.focused==true) | .num' 2>/dev/null
|
||||
else
|
||||
echo "1"
|
||||
fi
|
||||
}
|
||||
|
||||
# Determine session name based on monitor and workspace
|
||||
get_session_name() {
|
||||
local monitor=$(get_current_monitor)
|
||||
local workspace=$(get_current_workspace)
|
||||
|
||||
# Fallback if we can't get monitor/workspace info
|
||||
if [ -z "$monitor" ] || [ "$monitor" = "null" ]; then
|
||||
monitor="default"
|
||||
fi
|
||||
if [ -z "$workspace" ] || [ "$workspace" = "null" ]; then
|
||||
workspace="1"
|
||||
fi
|
||||
|
||||
# Clean monitor name (remove special characters)
|
||||
monitor_clean=$(echo "$monitor" | sed 's/[^a-zA-Z0-9-]/_/g')
|
||||
|
||||
# Map monitors to logical screen names
|
||||
case "$monitor_clean" in
|
||||
"eDP_1"|"eDP1")
|
||||
screen="laptop"
|
||||
;;
|
||||
"DVI_I_2_2"|"HDMI_1"|"HDMI1"|"DP_1"|"DP1")
|
||||
screen="external1"
|
||||
;;
|
||||
"DVI_I_1_1"|"HDMI_2"|"HDMI2"|"DP_2"|"DP2")
|
||||
screen="external2"
|
||||
;;
|
||||
"default")
|
||||
screen="main"
|
||||
;;
|
||||
*)
|
||||
screen="${monitor_clean}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Create session name: screen-workspace (e.g., laptop-1, external1-5)
|
||||
if [ "$screen" = "main" ]; then
|
||||
echo "main"
|
||||
else
|
||||
echo "${screen}-ws${workspace}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Launch alacritty with tmux
|
||||
launch_terminal() {
|
||||
local session_name=$(get_session_name)
|
||||
|
||||
# Debug logging (remove after testing)
|
||||
echo "Launching terminal with session: $session_name" >> /tmp/smart-terminal.log
|
||||
|
||||
# Check if alacritty exists
|
||||
ALACRITTY_PATH="/home/jens/.cargo/bin/alacritty"
|
||||
if [ ! -x "$ALACRITTY_PATH" ]; then
|
||||
ALACRITTY_PATH=$(which alacritty 2>/dev/null)
|
||||
if [ -z "$ALACRITTY_PATH" ]; then
|
||||
# Fallback to xterm or another terminal
|
||||
echo "Alacritty not found, falling back to xterm" >> /tmp/smart-terminal.log
|
||||
xterm -e tmux new-session -A -s "$session_name" &
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if tmux session exists
|
||||
if tmux has-session -t "$session_name" 2>/dev/null; then
|
||||
# Session exists, attach to it
|
||||
"$ALACRITTY_PATH" --title "Terminal [$session_name]" -e tmux attach-session -t "$session_name" &
|
||||
else
|
||||
# Create new session with meaningful name
|
||||
"$ALACRITTY_PATH" --title "Terminal [$session_name]" -e tmux new-session -s "$session_name" &
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
launch_terminal
|
||||
229
i3/tmux-session-manager.sh
Executable file
229
i3/tmux-session-manager.sh
Executable file
@@ -0,0 +1,229 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Advanced tmux session management for multi-monitor setup
|
||||
# Provides utilities for managing monitor-specific tmux sessions
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# List all tmux sessions with their status
|
||||
list_sessions() {
|
||||
echo -e "${BLUE}=== Tmux Sessions by Screen ===${NC}"
|
||||
|
||||
# Group sessions by screen
|
||||
for screen in laptop external1 external2; do
|
||||
sessions=$(tmux list-sessions 2>/dev/null | grep "^${screen}-" | cut -d: -f1)
|
||||
if [ ! -z "$sessions" ]; then
|
||||
echo -e "\n${GREEN}${screen}:${NC}"
|
||||
while IFS= read -r session; do
|
||||
workspace=$(echo "$session" | cut -d- -f2)
|
||||
attached=""
|
||||
if tmux list-sessions 2>/dev/null | grep "^${session}:" | grep -q "(attached)"; then
|
||||
attached=" ${YELLOW}[attached]${NC}"
|
||||
fi
|
||||
echo -e " • ${session}${attached}"
|
||||
done <<< "$sessions"
|
||||
fi
|
||||
done
|
||||
|
||||
# Show other sessions
|
||||
other_sessions=$(tmux list-sessions 2>/dev/null | grep -v -E "^(laptop|external1|external2)-" | cut -d: -f1)
|
||||
if [ ! -z "$other_sessions" ]; then
|
||||
echo -e "\n${BLUE}Other sessions:${NC}"
|
||||
while IFS= read -r session; do
|
||||
attached=""
|
||||
if tmux list-sessions 2>/dev/null | grep "^${session}:" | grep -q "(attached)"; then
|
||||
attached=" ${YELLOW}[attached]${NC}"
|
||||
fi
|
||||
echo -e " • ${session}${attached}"
|
||||
done <<< "$other_sessions"
|
||||
fi
|
||||
}
|
||||
|
||||
# Kill all sessions for a specific screen
|
||||
kill_screen_sessions() {
|
||||
local screen=$1
|
||||
if [ -z "$screen" ]; then
|
||||
echo -e "${RED}Error: Please specify a screen (laptop, external1, external2)${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
sessions=$(tmux list-sessions 2>/dev/null | grep "^${screen}-" | cut -d: -f1)
|
||||
if [ -z "$sessions" ]; then
|
||||
echo -e "${YELLOW}No sessions found for screen: ${screen}${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Killing all sessions for ${screen}...${NC}"
|
||||
while IFS= read -r session; do
|
||||
tmux kill-session -t "$session" 2>/dev/null
|
||||
echo -e " ${RED}✗${NC} Killed: $session"
|
||||
done <<< "$sessions"
|
||||
}
|
||||
|
||||
# Rename a session
|
||||
rename_session() {
|
||||
local old_name=$1
|
||||
local new_name=$2
|
||||
|
||||
if [ -z "$old_name" ] || [ -z "$new_name" ]; then
|
||||
echo -e "${RED}Error: Usage: rename_session <old_name> <new_name>${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if tmux has-session -t "$old_name" 2>/dev/null; then
|
||||
tmux rename-session -t "$old_name" "$new_name"
|
||||
echo -e "${GREEN}✓${NC} Renamed: $old_name → $new_name"
|
||||
else
|
||||
echo -e "${RED}Error: Session '$old_name' not found${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Switch to a different session
|
||||
switch_session() {
|
||||
local session_name=$1
|
||||
|
||||
if [ -z "$session_name" ]; then
|
||||
# Interactive session picker using fzf if available
|
||||
if command -v fzf &> /dev/null; then
|
||||
session_name=$(tmux list-sessions -F "#{session_name}" 2>/dev/null | fzf --prompt="Select session: ")
|
||||
else
|
||||
echo -e "${RED}Error: Please specify a session name${NC}"
|
||||
list_sessions
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -z "$session_name" ] && tmux has-session -t "$session_name" 2>/dev/null; then
|
||||
if [ -n "$TMUX" ]; then
|
||||
tmux switch-client -t "$session_name"
|
||||
else
|
||||
tmux attach-session -t "$session_name"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}Error: Session '$session_name' not found${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Create a new session for current monitor/workspace
|
||||
new_session_here() {
|
||||
# Source the functions from smart-terminal.sh
|
||||
source /home/jens/.config/i3/smart-terminal.sh
|
||||
local session_name=$(get_session_name)
|
||||
|
||||
if tmux has-session -t "$session_name" 2>/dev/null; then
|
||||
echo -e "${YELLOW}Session '$session_name' already exists${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
tmux new-session -d -s "$session_name"
|
||||
echo -e "${GREEN}✓${NC} Created new session: $session_name"
|
||||
}
|
||||
|
||||
# Clean up detached sessions
|
||||
cleanup_detached() {
|
||||
local detached=$(tmux list-sessions 2>/dev/null | grep -v "(attached)" | cut -d: -f1)
|
||||
|
||||
if [ -z "$detached" ]; then
|
||||
echo -e "${GREEN}No detached sessions to clean up${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Found detached sessions:${NC}"
|
||||
echo "$detached"
|
||||
echo -e "\n${YELLOW}Kill all detached sessions? (y/N)${NC}"
|
||||
read -r response
|
||||
|
||||
if [[ "$response" =~ ^[Yy]$ ]]; then
|
||||
while IFS= read -r session; do
|
||||
tmux kill-session -t "$session" 2>/dev/null
|
||||
echo -e " ${RED}✗${NC} Killed: $session"
|
||||
done <<< "$detached"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main menu
|
||||
show_menu() {
|
||||
echo -e "${BLUE}=== Tmux Session Manager ===${NC}"
|
||||
echo "1. List all sessions"
|
||||
echo "2. Switch to session"
|
||||
echo "3. Kill screen sessions"
|
||||
echo "4. Rename session"
|
||||
echo "5. Create session for current workspace"
|
||||
echo "6. Cleanup detached sessions"
|
||||
echo "7. Exit"
|
||||
echo -n "Select option: "
|
||||
}
|
||||
|
||||
# Main execution
|
||||
case "$1" in
|
||||
list)
|
||||
list_sessions
|
||||
;;
|
||||
kill-screen)
|
||||
kill_screen_sessions "$2"
|
||||
;;
|
||||
rename)
|
||||
rename_session "$2" "$3"
|
||||
;;
|
||||
switch)
|
||||
switch_session "$2"
|
||||
;;
|
||||
new)
|
||||
new_session_here
|
||||
;;
|
||||
cleanup)
|
||||
cleanup_detached
|
||||
;;
|
||||
*)
|
||||
if [ -z "$1" ]; then
|
||||
# Interactive mode
|
||||
while true; do
|
||||
show_menu
|
||||
read -r option
|
||||
case $option in
|
||||
1) list_sessions ;;
|
||||
2)
|
||||
echo -n "Session name: "
|
||||
read -r session
|
||||
switch_session "$session"
|
||||
;;
|
||||
3)
|
||||
echo -n "Screen (laptop/external1/external2): "
|
||||
read -r screen
|
||||
kill_screen_sessions "$screen"
|
||||
;;
|
||||
4)
|
||||
echo -n "Old name: "
|
||||
read -r old
|
||||
echo -n "New name: "
|
||||
read -r new
|
||||
rename_session "$old" "$new"
|
||||
;;
|
||||
5) new_session_here ;;
|
||||
6) cleanup_detached ;;
|
||||
7) exit 0 ;;
|
||||
*) echo -e "${RED}Invalid option${NC}" ;;
|
||||
esac
|
||||
echo
|
||||
done
|
||||
else
|
||||
echo "Usage: $0 [command] [args]"
|
||||
echo "Commands:"
|
||||
echo " list - List all sessions"
|
||||
echo " kill-screen <screen> - Kill all sessions for a screen"
|
||||
echo " rename <old> <new> - Rename a session"
|
||||
echo " switch <session> - Switch to a session"
|
||||
echo " new - Create session for current workspace"
|
||||
echo " cleanup - Cleanup detached sessions"
|
||||
echo ""
|
||||
echo "Run without arguments for interactive mode"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user