-
-
Save dedsm/610a004d896cac3a93c59558a8326dd9 to your computer and use it in GitHub Desktop.
import argparse | |
from i3ipc import Connection | |
sway = Connection() | |
outputs = [o for o in sway.get_outputs() if o.active] | |
def focus_monitor(args): | |
indices = {"left": 0, "center": 1, "right": 2} | |
orientation = indices[args.orientation] | |
if len(outputs) <= 1 or len(outputs) < orientation+1: | |
print(len(outputs)) | |
return | |
sorted_outputs = sorted(outputs, key=lambda x: x.rect.x) | |
output = sorted_outputs[orientation] | |
sway.command(f"workspace {output.current_workspace}") | |
def send_to_monitor(args): | |
indices = {"left": 0, "center": 1, "right": 2} | |
orientation = indices[args.orientation] | |
if len(outputs) <= 1 or len(outputs) < orientation+1: | |
print(len(outputs)) | |
return | |
sorted_outputs = sorted(outputs, key=lambda x: x.rect.x) | |
output = sorted_outputs[orientation] | |
sway.command(f"move container to workspace {output.current_workspace}") | |
def switch_workspace(args): | |
workspaces = sway.get_workspaces() | |
workspaces_by_name = {w.name: w for w in workspaces} | |
focused_workspace = next((w for w in workspaces if w.focused)) | |
destination = args.workspace | |
if focused_workspace.name == destination: | |
return | |
if destination not in workspaces_by_name: | |
# workspace doesn't exist | |
sway.command(f"workspace {destination}") | |
return | |
target_workspace = workspaces_by_name[destination] | |
destination_output = focused_workspace.output | |
source_output = target_workspace.output | |
if destination_output == source_output: | |
sway.command(f"workspace {destination}") | |
return | |
# workspace belongs to a different output | |
if target_workspace.visible: | |
# the workspace we want in the current output is | |
# being displayed in another output, so we swap | |
commands = [ | |
"workspace ___temp___", | |
f"move workspace to output {source_output}", | |
f"workspace {destination}", | |
f"move workspace to output {destination_output}", | |
f"workspace {focused_workspace.name}", | |
f"move workspace to output {source_output}", | |
f"workspace {destination}", | |
] | |
command = ";".join(commands) | |
sway.command(command) | |
else: | |
# the workspace is in a different output but hidden | |
# bring it to the destination output, no need for temp | |
# since we know there's at least one more | |
commands = [ | |
f"workspace {destination}", | |
f"move workspace to output {destination_output}" | |
] | |
command = ";".join(commands) | |
sway.command(command) | |
parser = argparse.ArgumentParser(description="Process custom sway commands") | |
subparsers = parser.add_subparsers(help="sub-command help") | |
output_choose = subparsers.add_parser( | |
"monitor", | |
help="pick monitor in X orientation order" | |
) | |
output_choose.add_argument( | |
"orientation", | |
type=str, | |
choices=["left", "center", "right"] | |
) | |
output_choose.set_defaults(func=focus_monitor) | |
send_to_output = subparsers.add_parser( | |
"send_to_output", | |
help="pick monitor in X orientation order" | |
) | |
send_to_output.add_argument( | |
"orientation", | |
type=str, | |
choices=["left", "center", "right"] | |
) | |
send_to_output.set_defaults(func=send_to_monitor) | |
workspace_choose = subparsers.add_parser( | |
"workspace", | |
help="switch workspace" | |
) | |
workspace_choose.add_argument( | |
"workspace", | |
type=str | |
) | |
workspace_choose.set_defaults(func=switch_workspace) | |
args = parser.parse_args() | |
args.func(args) |
Thanks a lot, this is perfect! I finally gave up resistance and moved from X to wayland and from xmonad to sway. This script was the last missing piece I needed to be happy with the move :)
I'm glad it could help someone @apirogov :)
Hey, I wrote the same thing for hyprland (https://github.com/hyprwm/contrib/blob/main/try_swap_workspace/try_swap_workspace). I have the same user story as you do, coming from Xmonad to wayland. I am having trouble with hyprlands dpms and therefore went to sway.
Although maybe I am mistaken but Xmonad has a way to send a window one output to the left/right. So when the window is on the left output, sending it one output to the right means it ends of on the center screen. Doing it again would send it to the right screen.
// edit: I hacked this together real quick:
#!/usr/bin/env python
import argparse
from i3ipc import Connection
sway = Connection()
outputs = [o for o in sway.get_outputs() if o.active]
def focus_monitor(args):
indices = {"left": 0, "center": 1, "right": 2}
orientation = indices[args.orientation]
if len(outputs) <= 1 or len(outputs) < orientation+1:
print(len(outputs))
return
sorted_outputs = sorted(outputs, key=lambda x: x.rect.x)
output = sorted_outputs[orientation]
sway.command(f"workspace {output.current_workspace}")
def send_to_monitor(args):
indices = {"left": 0, "center": 1, "right": 2}
orientation = indices[args.orientation]
if len(outputs) <= 1 or len(outputs) < orientation+1:
print(len(outputs))
return
sorted_outputs = sorted(outputs, key=lambda x: x.rect.x)
output = sorted_outputs[orientation]
sway.command(f"move container to workspace {output.current_workspace}")
def send_to_direction(args):
indices = {"left": -1, "right": 1}
direction = indices[args.direction]
workspaces = sway.get_workspaces()
focused_workspace = next((w for w in workspaces if w.focused))
focused_output = next((o for o in outputs if o.focused))
sorted_outputs = sorted(outputs, key=lambda x: x.rect.x)
target_output_idx = -1
for idx in range(len(sorted_outputs)):
o = sorted_outputs[idx]
if o == focused_output:
if idx + direction > len(outputs)-1:
target_output_idx = 0
elif (idx + direction < 0):
target_output_idx = len(outputs)-1
else:
target_output_idx = idx + direction
break
target_output = sorted_outputs[target_output_idx]
sway.command(f"move container to workspace {target_output.current_workspace}")
def switch_workspace(args):
workspaces = sway.get_workspaces()
workspaces_by_name = {w.name: w for w in workspaces}
focused_workspace = next((w for w in workspaces if w.focused))
destination = args.workspace
if focused_workspace.name == destination:
return
if destination not in workspaces_by_name:
# workspace doesn't exist
sway.command(f"workspace {destination}")
return
target_workspace = workspaces_by_name[destination]
destination_output = focused_workspace.output
source_output = target_workspace.output
if destination_output == source_output:
sway.command(f"workspace {destination}")
return
# workspace belongs to a different output
if target_workspace.visible:
# the workspace we want in the current output is
# being displayed in another output, so we swap
commands = [
"workspace ___temp___",
f"move workspace to output {source_output}",
f"workspace {destination}",
f"move workspace to output {destination_output}",
f"workspace {focused_workspace.name}",
f"move workspace to output {source_output}",
f"workspace {destination}",
]
command = ";".join(commands)
sway.command(command)
else:
# the workspace is in a different output but hidden
# bring it to the destination output, no need for temp
# since we know there's at least one more
commands = [
f"workspace {destination}",
f"move workspace to output {destination_output}"
]
command = ";".join(commands)
sway.command(command)
parser = argparse.ArgumentParser(description="Process custom sway commands")
subparsers = parser.add_subparsers(help="sub-command help")
output_choose = subparsers.add_parser(
"monitor",
help="pick monitor in X orientation order"
)
output_choose.add_argument(
"orientation",
type=str,
choices=["left", "center", "right"]
)
output_choose.set_defaults(func=focus_monitor)
send_to_output = subparsers.add_parser(
"send_to_output",
help="pick monitor in X orientation order"
)
send_to_output.add_argument(
"orientation",
type=str,
choices=["left", "center", "right"]
)
send_to_output.set_defaults(func=send_to_monitor)
send_to_dir = subparsers.add_parser(
"send_to_direction",
help="pick monitor in X orientation order"
)
send_to_dir.add_argument(
"direction",
type=str,
choices=["left", "right"]
)
send_to_dir.set_defaults(func=send_to_direction)
workspace_choose = subparsers.add_parser(
"workspace",
help="switch workspace"
)
workspace_choose.add_argument(
"workspace",
type=str
)
workspace_choose.set_defaults(func=switch_workspace)
args = parser.parse_args()
args.func(args)
This does the movement to the left/ right monitor to the currently focused monitor. I don't know python, so that is pretty rough and done in a C way I guess.
Usage is
bindsym Control+comma exec ~/.config/sway/i3xmonadhelper send_to_direction left
bindsym Control+period exec ~/.config/sway/i3xmonadhelper send_to_direction right
(change path accordingly)
@Schievel1 I never used that with xmonad (sending to the right/left) but maybe it has.
I also used something similar in hyprland but there was already a plugin for this, and later on they added it in hyprland itself, this is my hyprland config for similar functionality:
"$mod, W, focusmonitor, l"
"$mod, E, focusmonitor, r"
"$mod SHIFT, W, movewindow, mon:l"
"$mod SHIFT, E, movewindow, mon:r"
Thanks a lot, this is perfect! I finally gave up resistance and moved from X to wayland and from xmonad to sway. This script was the last missing piece I needed to be happy with the move :)