# I, Ian Kelling, follow the GNU license recommendations at # https://www.gnu.org/licenses/license-recommendations.en.html. They # recommend that small programs, < 300 lines, be licensed under the # Apache License 2.0. This file contains or is part of one or more small # programs. If a small program grows beyond 300 lines, I plan to change # to a recommended GPL license. # Copyright 2024 Ian Kelling # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #!/usr/bin/python3 # There are only 2 cases where I want single window split containers. # # * just before creating a new window in it. # # * When I want to make 1 window a split container and bring an existing # window into it. In vanilla i3, this is super awkward. Usually, you are # starting out focused on the window you want to move into the # container. So, you focus the window which is to become a container, # split it, focus the window you want to join the container, move it # into that container. 4 actions, totally annoying. Lets simplify this # to 2 actions, a key to say what split we want, then a key to say which # direction to move the current window. Since we have a hook that erases # all single window split containers on focus change, we can consider a # single window split container to indicate the split we want. # # import sys from i3ipc import Connection, Event # for debugging from pprint import pprint import os def find_parent(i3, window_id): """ Find the parent of a given window id """ def finder(con, parent, gp): if con.id == window_id: return (parent, gp) for node in con.nodes: res = finder(node, con, parent) if res: return res return None return finder(i3.get_tree(), None, None) def set_layout(i3): """ Set the layout/split for the currently focused window to either vertical or horizontal, depending on its width/height """ direction = sys.argv[1] win = i3.get_tree().find_focused() parent, gp = find_parent(i3, win.id) layout = parent.layout if (parent and gp and len(parent.nodes) == 1): exists = False if os.path.exists('/tmp/iank-i3-no-auto'): exists = True else: open('/tmp/iank-i3-no-auto', 'a') i3.command('focus ' + direction) if (layout == 'splith'): i3.command('split horizontal') elif (layout == 'splitv'): i3.command('split vertical') elif (layout == 'tabbed'): i3.command('split vertical') i3.command('layout tabbed') i3.command('[con_id=%s] focus' % win.id) i3.command('move ' + direction) if (not exists): os.remove('/tmp/iank-i3-no-auto') else: i3.command('move ' + direction) def main(): i3 = Connection() set_layout(i3) if __name__ == "__main__": main()