i3 improvements wip
[distro-setup] / i3-split-maybe
1 #!/usr/bin/python3
2
3 # This anticipates when we want to tab windows. There are 2 options of
4 # when to do it: just after a window is created, or just before a window
5 # is created.
6 #
7 # * Doing it after a window is created allows you to move a window into
8 # the split that only has 1 window, whereas the other way doesn't. For
9 # my use cases, I think I don't really want to move it into the split if
10 # it is a tabbed split. upon further reflection, I've determined that
11 # single window containers are inherently confusing because they tend to
12 # exist and get nested at unexpected times and then it is unclear how to
13 # get rid of them and what is going on and the benefit is generally not
14 # worth it. This command helps identify single window containers during
15 # testing: /a/opt/i3ipc-python/examples/i3-debug-console.py
16 #
17 # * Doing it just before a windows is created, you need to call this
18 # script, which means wrapping launch of a program, which I have no way
19 # to do for all cases, I just do it for the common programs I have bound
20 # to keys in i3.
21 #
22 # * Note: doing it just before a window is created also leaves that split behind if
23 # the window is closed, and I don't want single window splits hanging around,
24 # so I close them out in
25 #
26 # I have a keybind which disables both, it runs /b/ds/i3-auto-layout-toggle
27
28
29 import sys
30 import os
31 from i3ipc import Connection, Event
32 # for debugging
33 #from pprint import pprint
34
35
36 def find_parent(i3, window_id):
37 """
38 Find the parent of a given window id
39 """
40
41 def finder(con, parent, gp):
42 if con.id == window_id:
43 return (parent, gp)
44 for node in con.nodes:
45 res = finder(node, con, parent)
46 if res:
47 return res
48 return None
49
50 return finder(i3.get_tree(), None, None)
51
52
53 def set_layout(i3):
54 """
55 Set the layout/split for the currently
56 focused window to either vertical or
57 horizontal, depending on its width/height
58 """
59
60 if os.path.isfile("/tmp/iank-i3-no-auto"):
61 return
62
63 win = i3.get_tree().find_focused()
64 parent, gp = find_parent(i3, win.id)
65
66
67 workspace = win.workspace()
68 #pprint(vars(workspace.rect))
69
70 screen_width = workspace.rect.width
71 screen_height = workspace.rect.height
72 half_w = screen_width / 2 + 1
73 half_h = screen_height / 2 + 1
74
75 w = win.rect.width
76 h = win.rect.height
77 ph = parent.rect.height
78 pw = parent.rect.width
79
80 # There is potential for future use with < 1920, but I'm
81 # not thinking about it yet.
82 if ( screen_width < 1920 or parent.layout == 'tabbed' or gp.layout == 'tabbed'):
83 return
84
85 # print('d2: len(parent.nodes)', len(parent.nodes),' > 1',
86 # 'and ( ph ',ph,' > h + 10',h + 10,' or pw',pw,' > w',w,' )',
87 # 'and w <= half_w',half_w,'+ and h <= half_h',half_h)
88
89 # h + 10 because a tabbed window loses high compared to its parent.
90 # Note, it is redundant since we check above if the parent is tabbed,
91 # but just being cautious.
92 if (len(parent.nodes) > 1
93 and ( ph > h + 10 or pw > w )
94 and w <= half_w and h <= half_h ):
95 i3.command('split vertical, layout tabbed')
96 # print('d1: tabbed')
97
98
99 ### further potential use cases:
100
101 # We could automatically do a vertical split when there are 2 or 3
102 # horizontal windows.
103
104 # We could undo a vertical split when we close out windows.
105 # elif (( w == screen_width )); then
106 # # if we had 2 windows on screen, made them vertical splits, then
107 # # closed one, it stays vertical split, but we want it horizontal at
108 # # that point. So, make it horizontal here.
109 # m i3-msg "split horizontal"
110
111
112 def main():
113 i3 = Connection()
114 set_layout(i3)
115
116
117 if __name__ == "__main__":
118 main()