Skip to content

Instantly share code, notes, and snippets.

@omenius
Last active November 28, 2023 19:54
Show Gist options
  • Save omenius/36002dc4dc699016b11c71f7a956c02a to your computer and use it in GitHub Desktop.
Save omenius/36002dc4dc699016b11c71f7a956c02a to your computer and use it in GitHub Desktop.
better-i3-focus
#!/usr/bin/env python3
"""
This script imitates the native 'i3-msg focus [right/left]' functionality
with the exception that it totally ignores any non-visible tabs.
requires: pip install i3ipc
takes exactly one argument: [right|left]
"""
from sys import argv
if argv[1] == "right":
direction = 1
elif argv[1] == "left":
direction = -1
else:
exit()
from i3ipc import Connection
i3 = Connection()
# Recursively look for the last focused item inside a node
def find_focused(node):
if node.focus:
return find_focused( node.find_by_id(node.focus[0]) )
else:
return node
# Find the window on the right/left side of the given node
def find_neighbor_window(node):
child = node
container = node.parent
while container and container.layout != "output":
if( container.layout != "splitv"):
current_node_idx = container.nodes.index(child)
# Find node on argv[1] side of current node if exists
dest_idx = current_node_idx + direction
if dest_idx != -1 and len(container.nodes) > dest_idx:
return find_focused(container.nodes[dest_idx])
# Go to parent and try again if not exhausted
child = container
container = container.parent
# Finds the child of the nearest parent tab container or "tab page"
def find_tab_page(node):
container = node
while container.parent:
if container.parent.layout == "tabbed":
return container
container = container.parent
return
# Finds the appropriate tab container where we can perform the move
def find_correct_node(node):
tab_page = find_tab_page(node)
if tab_page is None:
return
neighbor_win = find_neighbor_window(node)
if neighbor_win is None or neighbor_win in tab_page.descendants():
return
tab_container = tab_page.parent
super_tab_container = find_correct_node(tab_container)
if super_tab_container:
return super_tab_container
else:
return tab_container
# Finally, do the magic
focused = i3.get_tree().find_focused()
super_node = find_correct_node(focused)
if super_node:
i3.command(f'[con_id="{super_node.id}"] focus, focus {argv[1]}')
else:
i3.command(f'focus {argv[1]}')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment