The i3 FAQ has migrated to https://github.com/i3/i3/discussions. All content here is read-only.
Ask Your Question
2

move focus from tabbed container to window which is currently displayed left of it

asked 2015-10-14 12:51:14 +0000

kyra gravatar image

Consider the following arrangement of windows:

AAAA|BB|CC

where B and C are in a tabbed container, A and this tabbed container are on a split-screen workspace and the focus is on C (which means the screen content is actually AAAA|CCCC).

What would be a good way of moving the focus to window A without changing the focus on the right half of the screen to B?

I would like to have something like 'move the focus to whatever is visible left of the currently focused window'. I already tried to use 'focus parent' a couple of times until the level where the 'move left' would accomplish what I wanted to do. However I found it difficult to find out to determine which parent level I have to focus on.

Is there a good way of achieving that?

(obviously I am not only interested in moving the focus left, but ideally in all four directions :P)

edit retag flag offensive close merge delete

3 answers

Sort by ยป oldest newest most voted
1

answered 2015-10-14 14:18:21 +0000

i3convert gravatar image

Possible solution: You can write a script that analyzes the output of i3-msg -t get_tree to figure out for you how many levels you have to go up first (Python has a nice library for parsing JSON, which is the format of the output of this command). Then the script could issue the command focus parent the right number of times, before doing focus left.

Alternately, it could just figure out the X11 id of the window you want to move the focus to and then just issue [id=???] focus, where ??? is the id.

I guess it would be nice to have two sets of left, right, up, down keys. $mod+arrows is the standard one, and Ctrl+$mod+arrows is the visual move focus, which doesn't switch tabs in the tabbed or stacking layout.

Workaround: What I have been doing in this kind of situation is to use the stacking layout for the right side of the screen (the command layout stacking). Then moving left/right doesn't change between windows B and C (you have to move up/down for that). Clearly, this is only a workaround that wouldn't work in more complicated situations and unfortunately a little more screen space gets wasted.

edit flag offensive delete link more
1

answered 2015-10-21 17:36:15 +0000

Anon1234 gravatar image

updated 2015-10-21 21:37:32 +0000

I wrote a small python script that uses i3-msg -t get_tree as was mentioned by @i3convert. It can toggle focus between visible windows. Also thanks to @airblader for his explanation on hidden windows feature.

Usage:

# focus next visible window
bindsym $mod+n exec --no-startup-id ~/.i3/focus_next_visible.py
# focus previous visible window
bindsym $mod+Shift+n exec --no-startup-id ~/.i3/focus_next_visible.py reverse

Code:

#!/usr/bin/env python3

"""
focus_next_visible.py - toggles focus between visible windows on workspace

 - requires https://github.com/acrisci/i3ipc-python

"""
from sys import argv
from itertools import cycle
from subprocess import check_output

import i3ipc


def get_windows_on_ws(conn):
    return filter(lambda x: x.window,
                  conn.get_tree().find_focused().workspace().descendents())


def find_visible_windows(windows_on_workspace):
    visible_windows = []
    for w in windows_on_workspace:
        xprop = check_output(['xprop', '-id', str(w.window)]).decode()

        if '_NET_WM_STATE_HIDDEN' in xprop:
            print(w.name, 'is not visible')
        else:
            print(w.name, 'is visible')
            visible_windows.append(w)

    return visible_windows


if __name__ == '__main__':

    conn = i3ipc.Connection()

    visible = find_visible_windows(get_windows_on_ws(conn))

    if len(argv) > 1 and argv[1] == "reverse":
        cv = cycle(reversed(visible))
    else:
        cv = cycle(visible)

    for w in cv:
        if w.focused:
            focus_to = next(cv)
            conn.command('[id="%d"] focus' % focus_to.window)
            print("Moving focus to", focus_to.name)
            break
edit flag offensive delete link more
1

answered 2015-10-14 13:09:22 +0000

While in 'C' you can focus parent container and then move the focus left.

Assuming you have something like that in your bindings :

bindsym $mod+q focus parent
bindsym $mod+h focus left

You would use mod+q to focus C's parent container, and mod+h to move focus to A.

edit flag offensive delete link more

Comments

I think it is not always obvious with complicated layouts how many times you have to press $mod+q.

i3convert gravatar imagei3convert ( 2015-10-14 13:57:40 +0000 )edit
1

I usually look at the windows' titles and borders, as they are highlighted when using 'focus parent'. Maybe it's because I don't use very complicated layouts but I feel this is a sufficient hint.

Philippe Virouleau gravatar imagePhilippe Virouleau ( 2015-10-14 14:27:18 +0000 )edit

@PV: I've been doing that too. The problem is that I'm sometimes left with empty (i.e., one node) levels in between (after closing some windows), so this requires multiple `focus parent` and the depth is unclear. So I overshoot with `focus parent` and fix this with a single `focus child`.

i3convert gravatar imagei3convert ( 2015-10-14 16:21:02 +0000 )edit
1

So I think there is a value to having a "visual" left, right, etc. procedures that work with a fixed number of keystrokes and require no thinking :)

i3convert gravatar imagei3convert ( 2015-10-14 16:29:15 +0000 )edit

Question Tools

1 follower

Stats

Asked: 2015-10-14 12:51:14 +0000

Seen: 232 times

Last updated: Oct 21