-
-
Save haselwarter/5e1b16bf6288a4a0376ca6480da4d6d6 to your computer and use it in GitHub Desktop.
#!/usr/bin/bash | |
# Goal: move workspace $1 to the currently focused output, move the workspace on the current output | |
# to the output where $1 was. | |
# The workspace we want to end up on | |
dest_ws=$1 | |
# The output where the destination ws resides | |
output_of_dest_ws=$(i3-msg -t get_workspaces | jq .[] | jq -r 'select(.name == "'$dest_ws'").output') | |
# The currently focused output | |
current_output=$(i3-msg -t get_workspaces | jq .[] | jq -r "select(.focused == true).output") | |
# The workspace on the current output | |
current_ws=$(i3-msg -t get_workspaces | jq .[] | jq -r "select(.focused == true).name") | |
# Send away the current workspace | |
i3-msg move workspace to output $output_of_dest_ws | |
# Select the destination workspace | |
i3-msg workspace $dest_ws | |
# Move the destination workspace to what was the current output in the beginning | |
i3-msg move workspace to output $current_output | |
# Re-activate the destination workspace | |
# sleep 0.2 | |
i3-msg workspace $dest_ws |
#!/bin/bash
dest_ws=$1
json=$(i3-msg -t get_workspaces)
output_of_dest_ws=$(jq -r ".[] | select(.name == \"$dest_ws\").output" <<< "$json")
[[ $output_of_dest_ws ]] \
|| { echo "could not find dest_ws: $dest_ws" ; exit ;}
current_output=$(jq -r ".[] | select(.focused == true).output" <<< "$json")
[[ $output_of_dest_ws = "$current_output" ]] || {
msg+="move workspace to output $output_of_dest_ws;"
msg+="[workspace=$dest_ws] move workspace to output $current_output;"
}
msg+="workspace $dest_ws"
i3-msg "$msg"
one i3-msg, two (or one) jq, re-use the json, trims the time a bit. but jq is s l o w...
0 jq pure bash version, gotta go fast:
#!/bin/bash
dest_ws=$1
json=$(i3-msg -t get_workspaces)
dest_re='"name":"'"$dest_ws"'[^}]+},"output":"([^"]+)'
current_re='"focused":true[^}]+},"output":"([^"]+)'
[[ $json =~ $current_re ]] && current_output=${BASH_REMATCH[1]}
if [[ $json =~ $dest_re ]]; then
output_of_dest_ws=${BASH_REMATCH[1]}
[[ $output_of_dest_ws = "$current_output" ]] || {
msg+="move workspace to output $output_of_dest_ws;"
msg+="[workspace=$dest_ws] move workspace to output $current_output;"
}
msg+="workspace $dest_ws"
else
msg+="workspace $dest_ws;"
msg+="[workspace=$dest_ws] move workspace to output $current_output;"
fi
i3-msg "$msg"
edit: script will now create the dest_ws if it doesn't exist and if it isn't on current_output (it was assigned to a different output etc) it will still be moved to the current one.
i refactored and annotated my version:
#!/bin/bash
# Switches workspaces in i3 like xmonad.
# Always bring the requested workspace to the
# focused monitor ("output" in i3's terminology).
# If the requested workspace is on another monitor,
# the current workspace and requested workspace
# will swap positions with each other.
# ~/.config/i3/config
# set $ws1 "1"
#
# from this:
# bindsym $mod+1 workspace number $ws1
#
# to this:
# bindsym $mod+1 exec --no-startup-id wsmove $ws1
#
# (assuming this script is named 'wsmove' and available in $PATH)
# -----------------------------------------------
declare ws_target # $1 == target workspace
declare op_current # current output
declare op_target # target output
declare re_target # regex to get op_target
declare re_current # regex to get op_current
declare msg # commands passed to i3-msg
ws_target=$1
[[ $ws_target ]] || {
echo "usage: ${0##*/} WORKSPACE" >&2
exit 1
}
json=$(i3-msg -t get_workspaces)
re_target='"name":"'"$ws_target"'[^}]+},"output":"([^"]+)'
re_current='"focused":true[^}]+},"output":"([^"]+)'
[[ $json =~ $re_current ]] && op_current=${BASH_REMATCH[1]}
if [[ $json =~ $re_target ]]; then
op_target=${BASH_REMATCH[1]}
# only swap monitors if the workspaces are on
# different outputs
[[ $op_target = "$op_current" ]] || {
# move the current workspace to op_target
# we don't need to know the current workspace
# name for this to work.
msg+="move workspace to output $op_target;"
msg+="[workspace=$ws_target] move workspace to output $op_current;"
}
else # ws_target doesn't exist
# create ws_target
msg+="workspace --no-auto-back-and-forth $ws_target;"
# move ws_target to op_current in case it was
# "assigned" to a different output. swapping
# outputs is probably not what we want
msg+="[workspace=$ws_target] move workspace to output $op_current;"
fi
# always focus ws_target
msg+="workspace --no-auto-back-and-forth $ws_target"
i3-msg "$msg"
so i found this https://github.com/altdesktop/i3ipc-python and this works perfectly for one of my scripts, this swapping one
#!/usr/bin/env python3
# Swap visible workspace on two monitors
import i3ipc
import sys
# Create the Connection object that can be used to send commands and subscribe
# to events.
i3 = i3ipc.Connection()
workspaces = i3.get_workspaces()
focused = None
notfocused = None
for workspace in workspaces:
if workspace.visible and workspace.focused :
focused = workspace
elif workspace.visible:
notfocused = workspace
# checking if any of the workspace is not availiable, in case of single monitor
if notfocused == None or focused == None:
sys.exit(-1)
command1 = "[workspace=" + notfocused.name + "] " + "move --no-auto-back-and-forth workspace to output " + focused.output
command2 = "[workspace=" + focused.name + "] " + "move --no-auto-back-and-forth workspace to output " + notfocused.output
command1_ret = i3.command(command1)
if not command1_ret[0].success:
print(command1_ret[0].error)
sys.exit(-1)
command2_ret = i3.command(command2)
if not command2_ret[0].success:
print(command1_ret[0].error)
sys.exit(-2)
command3 = "workspace " + notfocused.name
command4 = "workspace " + focused.name
command3_ret = i3.command(command3)
if not command3_ret[0].success:
print(command3_ret[0].error)
sys.exit(-1)
command4_ret = i3.command(command4)
if not command4_ret[0].success:
print(command4_ret[0].error)
sys.exit(-1)
i got no error, i ran it nearly 50 times, in dfferent cases, so you can make something like this for your case.
that python script takes ~300ms to execute on my machine while my bash version takes ~40ms. Mine also does smarter tests, like why is the python script moving the target ws and judging by the result of the command if it was possible, it is easy to do without issuing a command. The bash script also has no dependencies, besides bash and i3-msg.
@budRich can you help me convert my python script to bash too, it is for following case,
i have two monitors, and when i press a keybind
i want to move workspace on unfocused output to focused one and
the workspace on focused output to unfoucsed one
like why is the python script moving the target ws and judging by the result of the command if it was possible
i gave my script for swapping, it's not same as yours, i was just giving a example of how i use the ipc-python
this is the script which works same as your one, ans yes it is slow than the bash one, that's why i want to convert my one to the bash one
#!/usr/bin/env python3
# Switches workspaces in i3 like xmonad.
# Always bring the requested workspace to the
# focused monitor ("output" in i3's terminology).
# If the requested workspace is on another monitor,
# the current workspace and requested workspace
# will swap positions with each other.
import i3ipc
import sys
# Create the Connection object that can be used to send commands and subscribe
# to events.
i3 = i3ipc.Connection()
ws_target = None
target = None # target workspace
focused = None # currently focused workspace
ws_target=sys.argv[1] # $1 == target workspace
workspaces = i3.get_workspaces()
for workspace in workspaces:
if workspace.name == ws_target:
target = workspace
if workspace.visible and workspace.focused:
focused = workspace
if target and focused:
break
if target == None:
# target doesn't exist
command1 = "workspace " + ws_target
command1_ret = i3.command(command1)
elif target.output != focused.output:
# only swap monitors if the workspaces are on different outputs
command1 = "[workspace=" + target.name + "] move workspace to output " + focused.output
command2 = "[workspace=" + focused.name + "] move workspace to output " + target.output
command1_ret = i3.command(command1)
command2_ret = i3.command(command2)
command3 = "workspace " + focused.name
command4 = "workspace " + target.name
command3_ret = i3.command(command3)
command4_ret = i3.command(command4)
else:
# target workspace on same monitor
command1 = "workspace --no-auto-back-and-forth " + target.name
command1_ret = i3.command(command1)
@totoro-ghost Yeah I think i can brew up that monitor ws swapper thing in bash. Sounds useful and more sober then the xmonad workspace summoning shenanigans :)
Suffers from the same race condition as far as I can tell. It'll work about 80% of the time but every once in a while the last message will be processed too soon and
$dest_ws
ends up not being selected.It's nice to save an invocation of
i3-msg
, I couldn't find the[workspace=...]
syntax in the i3 documentation.