apache-apply() {
for file; do
- if head -n1 "$file"| grep -E '^#!/bin/bash\b' &>/dev/null; then
+ if head -n1 "$file"| grep -E '^#!/' &>/dev/null; then
{
head -n1 "$file"
apache-header
#!/bin/bash
+# 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.
+
volume=0
f=/tmp/iank-i3-no-auto
+# todo: if it is disabled, update the status bar.
+
if [[ -e $f ]]; then
+ echo "enabling"
rm -f $f
else
+ echo "disabling"
touch $f
fi
#!/usr/bin/env python3
+# 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.
+
+
+
+# This gets rid of all single window containers.
+# If a single window container was nested in another,
+# it ignores that, but I don't generally expect to create them and
+# we change focus enough that we would kill them off.
+
+# Note: I spent a lot of time figuring out how to do this properly,
+# https://github.com/i3/i3/issues/3808 there are a bunch of links
+# which suggest either float toggle; float toggle, which doesn't put windows back in the same place, or doing a move, which only actually works if you are moving in a direction which does not have a container there, else your window joins the container, and .
+
+
import sys
import os
from i3ipc import Connection, Event
Find the parent of a given window id
"""
- def finder(con, parent, gp):
+ def finder(con, parent, workspace):
if con.id == window_id:
- return (parent, gp)
+ return (parent, workspace)
for node in con.nodes:
- res = finder(node, con, parent)
+ res = finder(node, con, con if con and con.type == 'workspace' else workspace)
if res:
return res
return None
return finder(i3.get_tree(), None, None)
+def kill_single_win_containers(i3, e, node, parent):
+ if len(parent.nodes) == 1 and len(node.nodes) == 0:
+ print("d1: killing parent")
+ # parent is a single window container, kill it.
+
+ # Note: based on testing,
+ # i3 takes care of not calling this program for
+ # events which we create within it. Otherwise,
+ # we could create our disabling file here
+ # and delete it later if it wasn't already there.
+ i3.command('[con_id=%s] focus' % node.id)
+ i3.command('mark i3ha')
+ i3.command('focus parent')
+ i3.command('focus parent')
+ i3.command('mark i3hb')
+ i3.command('[con_mark="i3ha"] focus')
+ i3.command('move window to mark i3hb')
+ i3.command('unmark i3ha')
+ i3.command('unmark i3hb')
+ # back to our original focus
+ i3.command('[con_id=%s] focus' % e.container.id)
+ elif len(node.nodes) >= 1:
+ for child in node.nodes:
+ kill_single_win_containers(i3, e, child, node)
+
+
+
def focus_hook(i3, e):
"""
Set the layout/split for the currently
if os.path.isfile("/tmp/iank-i3-no-auto"):
return
+ # I identify container vs a real windows by the fact that it has nodes.
+ # looking through the data, another notable difference is that it has
+ # 'window': None,
+ # 'window_type': None,
+
+ parent, workspace = find_parent(i3, e.container.id)
# debugging
- #pprint(vars(e))
+ #exit(0)
- parent, gp = find_parent(i3, e.container.id)
+ if not workspace:
+ return
+ #pprint(vars(workspace))
+ #print()
+ for pnode in workspace.nodes:
+ # debugging
+ # if (len(pnode.nodes) >= 1):
+ # print("pnodes: ", pnode.nodes)
- # This gets rid of tabbed container with single windows.
- #if (parent and gp and parent.layout == 'tabbed' and len(parent.nodes) == 1):
- # This gets rid of all single window containers.
- if (parent and gp and len(parent.nodes) == 1):
- i3.command('mark i3ha')
- i3.command('focus parent')
- i3.command('focus parent')
- i3.command('mark i3hb')
- i3.command('[con_mark="i3ha"] focus')
- i3.command('move window to mark i3hb')
- i3.command('unmark i3ha')
- i3.command('unmark i3hb')
+ for node in pnode.nodes:
+ kill_single_win_containers(i3, e, node, pnode)
def main():
i3 = Connection()
i3.on(Event.WINDOW_FOCUS, focus_hook)
+ # if we don't have move, and we move a window out of a container,
+ # leaving behind a single window container, then we move it back, it
+ # will go into the container. We could expect that if we do it
+ # quickly, but it would be unexpected after a few seconds and we
+ # forget that it was a container.
+ i3.on(Event.WINDOW_MOVE, focus_hook)
i3.main()
"""
win = i3.get_tree().find_focused()
+ # i don't use gp: todo: revert to original alternating_layout function
+ # which did not return gp.
parent, gp = find_parent(i3, win.id)
# instead of what we want. And in fact, the whole logic below is
# incorrect and based on testing which did not realize that fact.
#
- if (parent and gp and len(parent.nodes) == 1):
+ if (parent and parent.type == 'con' and len(parent.nodes) == 1):
# https://unix.stackexchange.com/questions/173754/how-to-move-a-window-up-to-the-level-of-its-parent-window-in-i3wm
i3.command('mark i3ha')
i3.command('focus parent')
#!/usr/bin/python3
+# 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.
+
+
# This anticipates when we want to tab windows. There are 2 options of
# when to do it: just after a window is created, or just before a window
# is created.
# so I close them out in
#
# I have a keybind which disables both, it runs /b/ds/i3-auto-layout-toggle
-
+#
import sys
import os
+# 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.
# 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
layout = parent.layout
if (parent and gp and len(parent.nodes) == 1):
- i3.command('focus ' + direction)
-
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')
i3.command('move ' + direction)
-
def main():
i3 = Connection()
set_layout(i3)
# todo: think whether this is useful: https://github.com/tmfink/i3-wk-switch
# todo: see comment by Jakstern551 here for tip about jumping to windows
+# https://old.reddit.com/r/i3wm/comments/k8m4k4/share_your_i3_tips_and_tricks_that_you_have/
# https://i3wm.org/docs/userguide.html#keybindings
#To get the current mapping of your keys, use xmodmap -pke. To
bindsym $mod+1 focus parent
bindsym $mod+shift+1 focus child
-# undo split: https://github.com/i3/i3/issues/3808
-bindsym $mod+grave floating toggle; floating toggle
+
+# note, i used to have a key: "floating toggle; floating toggle" to
+# as undo split, as suggested here https://github.com/i3/i3/issues/3808
+# but something
+#
+bindsym $mod+grave floating toggle
bindsym $mod+equal $ex "i3-set-layout splith"
# move firefox to current workspace.
# https://i3wm.org/docs/userguide.html#keybindings
#bindsym $mod+Shift+t move workspace to output up
bindsym $mod+Shift+t move workspace to output right
-# todo: consider a command that moves a window, and erases any single
-# container window left behind.
-
-# todo: consider a command which alters things as if the current window
-# had been created into a single window split. For horizontal split,
-# this would be like: focus left, split vertical, focus right, move
-# left. With that, we could totally eliminate single window containers.
-
bindsym $mod+g $ex "i3-set-layout tabbed"
bindsym $mod+x workspace 6
-# todo, in newer i3, make this split toggle
+# todo, in newer i3, consider split toggle
bindsym $mod+v split vertical
bindsym $mod+Shift+v split horizontal
#
# change focus between tiling / floating windows
bindcode $mod+shift+65 focus mode_toggle
-# Use Mouse+$mod to drag floating windows to their wanted position
-floating_modifier $mod
bindsym $mod+shift+h $ex /b/ds/stream-clip hc
bindsym $mod+j $ex "i3-split-maybe"; exec emacsclient -c
# title bars but no borders. i tried this out a bit
#default_border normal 0
-default_border pixel 4
+
+# default border is like 2 pixels
+default_border pixel
# for debugging
-default_border normal 10
+#default_border normal 10
# I dont see a way to make processing windows act like normal windows,
# this does it.
# this is the processing window for my app named focus.
for_window [class="focus" instance="focus"] floating disable
-# client.focused #4c7899 #285577 #ffffff #2e9ef4 #ff4400
-# client.focused_inactive #333333 #5f676a #ffffff #484e50 #DBEEF4
-# client.unfocused #333333 #222222 #888888 #292d2e #B8C8CD
+client.focused #4c7899 #285577 #ffffff #2e9ef4 #ff4400
+client.focused_inactive #333333 #5f676a #ffffff #484e50 #DBEEF4
+client.unfocused #333333 #222222 #888888 #292d2e #B8C8CD