Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any way to get element on 'right' or 'left' of a given element? #207

Open
omenius opened this issue Nov 26, 2023 · 1 comment
Open

Any way to get element on 'right' or 'left' of a given element? #207

omenius opened this issue Nov 26, 2023 · 1 comment

Comments

@omenius
Copy link

omenius commented Nov 26, 2023

So let's say we have a window, for example:
window = i3.get_tree().find_focused()
Now I'd like to know the .right and .left items relative to our window (if those windows exist anyway).
Meaning the windows where user would end up when invoking i3-msg focus right or i3-msg focus left

I'm sure there must be some way to deduce the .right and .left items, but it's beyond my limited imagination.

Why?
If you are familiar with the examples/focus-next-visible.py, I'm kind of trying to create a focus-right/left-visible.py.
I want to be able to navigate through tabbed containers without switching the visible tab, using the i3 movement keys. I have separate keybind for cycling through the tabs. I really love it like this.

Here you can see hacky interpretation of how I like it. It gets around the issue by simply trying out and navigating back when it opens a tab that was not visible to user. It's slow as pope and flickers like damn.

# i3mover.py --- usage example: 
# bindsym $mod+l exec --no-startup-id python /path/to/file/i3mover.py right
# bindsym $mod+h exec --no-startup-id python /path/to/file/i3mover.py left

import sys
from i3ipc import Connection
i3 = Connection()

if sys.argv[1] == "right":
    dir = "right"
    adir = "left"
elif sys.argv[1] == "left":
    dir = "left"
    adir = "right"
else:
    exit()

def find_hidden_windows(tree):
    from subprocess import check_output
    windows = filter(lambda x: x.window, tree)
    hidden_windows = []
    for w in windows:
        xprop = check_output(['xprop', '-id', str(w.window)]).decode()
        if '_NET_WM_STATE_HIDDEN' in xprop:
            hidden_windows.append(w.id)
    return hidden_windows

tree = i3.get_tree()
origin = tree.find_focused()
hidden_window_ids = find_hidden_windows(tree)

# do the initial move
i3.command(f'focus {dir}')

# check if the initial move got us to hidden window
if i3.get_tree().find_focused().id in hidden_window_ids:

    # find the parent tabbed container where we can perform the right/left move
    candidate = origin.parent
    while True:
        if candidate.layout == "tabbed":
            break
        candidate = candidate.parent

    # move back, focus the whole tab container and redo the initial move
    i3.command(f'[con_id="{origin.id}"] focus, [con_id="{candidate.id}"] focus, focus {dir}')
@omenius
Copy link
Author

omenius commented Nov 28, 2023

I figured how to implement it. It was hard and annoying, so for the record here is the code: https://gist.github.com/omenius/36002dc4dc699016b11c71f7a956c02a

The find_neighbor_window(window) finds the same window that i3-msg focus right/left finds, but it only looks from inside the output/workspace since that was enough for my case.

I think this is how i3 should work natively. There is a reason why most tiling managers have no tabs. Imo using tabs destroys the workflow if you don't have separate keybinds for cycling through the tabs and moving between not tabbed windows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant