Robert Cranston authored on 06/06/2026 11:06:46
Showing 5 changed files

... ...
@@ -1,4 +1,4 @@
1
-## Variables
1
+## Mod
2 2
 set $mod Mod4
3 3
 floating_modifier $mod
4 4
 
... ...
@@ -20,6 +20,12 @@ bindsym $mod+Shift+j move down
20 20
 bindsym $mod+Shift+k move up
21 21
 bindsym $mod+Shift+l move right
22 22
 
23
+## Resize window
24
+bindsym $mod+Control+h resize shrink width  10 px or 10 ppt
25
+bindsym $mod+Control+j resize grow   height 10 px or 10 ppt
26
+bindsym $mod+Control+k resize shrink height 10 px or 10 ppt
27
+bindsym $mod+Control+l resize grow   width  10 px or 10 ppt
28
+
23 29
 ## Focus parent
24 30
 bindsym $mod+a focus parent
25 31
 
... ...
@@ -57,7 +63,7 @@ bindsym $mod+Shift+r reload
57 63
 bindsym $mod+Control+r restart
58 64
 
59 65
 ## Exit
60
-bindsym $mod+Control+e exit
66
+# bindsym $mod+Control+e exit
61 67
 
62 68
 ## Terminal
63 69
 bindsym $mod+Return exec --no-startup-id $TERMINAL
... ...
@@ -107,18 +113,6 @@ bindsym $mod+Control+8 move container to workspace number  8; workspace number
107 113
 bindsym $mod+Control+9 move container to workspace number  9; workspace number  9
108 114
 bindsym $mod+Control+0 move container to workspace number 10; workspace number 10
109 115
 
110
-## Resize
111
-bindsym $mod+r mode "resize"
112
-mode "resize"
113
-{
114
-    bindsym Escape    mode "default"
115
-    bindsym Control+c mode "default"
116
-    bindsym h resize shrink width  10 px or 10 ppt
117
-    bindsym j resize grow   height 10 px or 10 ppt
118
-    bindsym k resize shrink height 10 px or 10 ppt
119
-    bindsym l resize grow   width  10 px or 10 ppt
120
-}
121
-
122 116
 ## Mark
123 117
 bindsym $mod+m mode "mark"
124 118
 mode "mark"
... ...
@@ -161,58 +155,118 @@ mode "mark"
161 155
     bindsym $mod+8 mark --add --toggle 8; mode "default"
162 156
     bindsym $mod+9 mark --add --toggle 9; mode "default"
163 157
     bindsym $mod+0 mark --add --toggle 0; mode "default"
164
-    bindsym      a [con_mark="a"] focus;  mode "default"
165
-    bindsym      b [con_mark="b"] focus;  mode "default"
166
-    bindsym      c [con_mark="c"] focus;  mode "default"
167
-    bindsym      d [con_mark="d"] focus;  mode "default"
168
-    bindsym      e [con_mark="e"] focus;  mode "default"
169
-    bindsym      f [con_mark="f"] focus;  mode "default"
170
-    bindsym      g [con_mark="g"] focus;  mode "default"
171
-    bindsym      h [con_mark="h"] focus;  mode "default"
172
-    bindsym      i [con_mark="i"] focus;  mode "default"
173
-    bindsym      j [con_mark="j"] focus;  mode "default"
174
-    bindsym      k [con_mark="k"] focus;  mode "default"
175
-    bindsym      l [con_mark="l"] focus;  mode "default"
176
-    bindsym      m [con_mark="m"] focus;  mode "default"
177
-    bindsym      n [con_mark="n"] focus;  mode "default"
178
-    bindsym      o [con_mark="o"] focus;  mode "default"
179
-    bindsym      p [con_mark="p"] focus;  mode "default"
180
-    bindsym      q [con_mark="q"] focus;  mode "default"
181
-    bindsym      r [con_mark="r"] focus;  mode "default"
182
-    bindsym      s [con_mark="s"] focus;  mode "default"
183
-    bindsym      t [con_mark="t"] focus;  mode "default"
184
-    bindsym      u [con_mark="u"] focus;  mode "default"
185
-    bindsym      v [con_mark="v"] focus;  mode "default"
186
-    bindsym      w [con_mark="w"] focus;  mode "default"
187
-    bindsym      x [con_mark="x"] focus;  mode "default"
188
-    bindsym      y [con_mark="y"] focus;  mode "default"
189
-    bindsym      z [con_mark="z"] focus;  mode "default"
190
-    bindsym      1 [con_mark="1"] focus;  mode "default"
191
-    bindsym      2 [con_mark="2"] focus;  mode "default"
192
-    bindsym      3 [con_mark="3"] focus;  mode "default"
193
-    bindsym      4 [con_mark="4"] focus;  mode "default"
194
-    bindsym      5 [con_mark="5"] focus;  mode "default"
195
-    bindsym      6 [con_mark="6"] focus;  mode "default"
196
-    bindsym      7 [con_mark="7"] focus;  mode "default"
197
-    bindsym      8 [con_mark="8"] focus;  mode "default"
198
-    bindsym      9 [con_mark="9"] focus;  mode "default"
199
-    bindsym      0 [con_mark="0"] focus;  mode "default"
158
+    bindsym a [con_mark="a"] focus; mode "default"
159
+    bindsym b [con_mark="b"] focus; mode "default"
160
+    bindsym c [con_mark="c"] focus; mode "default"
161
+    bindsym d [con_mark="d"] focus; mode "default"
162
+    bindsym e [con_mark="e"] focus; mode "default"
163
+    bindsym f [con_mark="f"] focus; mode "default"
164
+    bindsym g [con_mark="g"] focus; mode "default"
165
+    bindsym h [con_mark="h"] focus; mode "default"
166
+    bindsym i [con_mark="i"] focus; mode "default"
167
+    bindsym j [con_mark="j"] focus; mode "default"
168
+    bindsym k [con_mark="k"] focus; mode "default"
169
+    bindsym l [con_mark="l"] focus; mode "default"
170
+    bindsym m [con_mark="m"] focus; mode "default"
171
+    bindsym n [con_mark="n"] focus; mode "default"
172
+    bindsym o [con_mark="o"] focus; mode "default"
173
+    bindsym p [con_mark="p"] focus; mode "default"
174
+    bindsym q [con_mark="q"] focus; mode "default"
175
+    bindsym r [con_mark="r"] focus; mode "default"
176
+    bindsym s [con_mark="s"] focus; mode "default"
177
+    bindsym t [con_mark="t"] focus; mode "default"
178
+    bindsym u [con_mark="u"] focus; mode "default"
179
+    bindsym v [con_mark="v"] focus; mode "default"
180
+    bindsym w [con_mark="w"] focus; mode "default"
181
+    bindsym x [con_mark="x"] focus; mode "default"
182
+    bindsym y [con_mark="y"] focus; mode "default"
183
+    bindsym z [con_mark="z"] focus; mode "default"
184
+    bindsym 1 [con_mark="1"] focus; mode "default"
185
+    bindsym 2 [con_mark="2"] focus; mode "default"
186
+    bindsym 3 [con_mark="3"] focus; mode "default"
187
+    bindsym 4 [con_mark="4"] focus; mode "default"
188
+    bindsym 5 [con_mark="5"] focus; mode "default"
189
+    bindsym 6 [con_mark="6"] focus; mode "default"
190
+    bindsym 7 [con_mark="7"] focus; mode "default"
191
+    bindsym 8 [con_mark="8"] focus; mode "default"
192
+    bindsym 9 [con_mark="9"] focus; mode "default"
193
+    bindsym 0 [con_mark="0"] focus; mode "default"
200 194
 }
201 195
 
202
-## Borders
203
-default_border          pixel 0
204
-default_floating_border pixel 0
196
+## Floating
197
+for_window [title="^xzoom x[0-9]+$"] floating enable
205 198
 
206
-## Colors
207
-# https://notes.rcrnstn.net/colors.md
208
-#                       border    background text      indicator child_border
209
-client.focused          #ccccccff #000000ad  #ccccccff #00000000 #00000000
210
-client.focused_inactive #ccccccff #000000c0  #898989ff #00000000 #00000000
211
-client.placeholder      #898989ff #000000c0  #898989ff #00000000 #00000000
212
-client.unfocused        #898989ff #000000c0  #898989ff #00000000 #00000000
213
-client.urgent           #898989ff #000000c0  #ffbbbbff #00000000 #00000000
214
-client.background       #00000000
199
+## Borders
200
+default_border                 pixel 0
201
+default_floating_border        pixel 0
202
+for_window [class=".*"] border pixel 0
215 203
 
216 204
 ## Gaps
217 205
 gaps inner 10
218 206
 gaps outer -5
207
+# gaps top    21
208
+# gaps bottom 21
209
+
210
+## DEBUG
211
+# bindsym $mod+Shift+w border pixel 1; gaps inner all set  0; gaps outer all set  0;
212
+# bindsym $mod+Shift+e border pixel 0; gaps inner all set 10; gaps outer all set -5;
213
+bindsym $mod+Shift+w border pixel 1
214
+bindsym $mod+Shift+e border pixel 0
215
+
216
+## Colors
217
+# https://notes.rcrnstn.net/colors.md
218
+# RGBA
219
+# TODO: `set_from_resource` (with fallback)?
220
+
221
+# hex(round(0xff*0.75))      = hex(floor(0xff*0.75))      = '0xbf'
222
+# hex(round(0xff*0.75*0.90)) = hex(floor(0xff*0.75*0.90)) = '0xac'
223
+set $bgnone     #00000000
224
+set $bginactive #000000bf
225
+set $bgactive   #000000ac
226
+
227
+# OKLCH
228
+# Lightness: 0.0, 0.3740, 0.5609, 0.7479
229
+# Chroma 0.0, 0.0645, 0.1289
230
+# Hue: 29.23, 89.23, 149.23, 209.23, 269.23, 329.23
231
+set $bgblack    #000000ff
232
+set $bgred      #5e332cff
233
+set $bggreen    #264a2eff
234
+set $bgyellow   #4e3f12ff
235
+set $bgblue     #333f63ff
236
+set $bgmagenta  #543451ff
237
+set $bgcyan     #004a53ff
238
+set $bgwhite    #414141ff
239
+set $fgblack    #757575ff
240
+set $fgred      #f48c7dff
241
+set $fggreen    #6ec480ff
242
+set $fgyellow   #cea93fff
243
+set $fgblue     #8ca9ffff
244
+set $fgmagenta  #da8fd5ff
245
+set $fgcyan     #01c3d9ff
246
+set $fgwhite    #adadadff
247
+
248
+# Unkown (Lch_uv?)
249
+# set $bgblack    #000000ff
250
+# set $bgred      #553535ff
251
+# set $bggreen    #26442aff
252
+# set $bgyellow   #453d1eff
253
+# set $bgblue     #323e55ff
254
+# set $bgmagenta  #51344eff
255
+# set $bgcyan     #044545ff
256
+# set $bgwhite    #3e3e3eff
257
+# set $fgblack    #797979ff
258
+# set $fgred      #ffa6a7ff
259
+# set $fggreen    #7bd188ff
260
+# set $fgyellow   #d3be67ff
261
+# set $fgblue     #9dbfffff
262
+# set $fgmagenta  #f3a3ecff
263
+# set $fgcyan     #00d3d4ff
264
+# set $fgwhite    #bebebeff
265
+
266
+#                       border   background  text     indicator child_border
267
+client.focused          $fgwhite $bginactive $fgwhite $fgblack  $fgwhite
268
+client.focused_inactive $fgblack $bginactive $fgwhite $fgblack  $fgblack
269
+client.unfocused        $fgblack $bginactive $fgblack $fgblack  $fgblack
270
+client.placeholder      $fgblack $bginactive $fgblack $fgblack  $fgblack
271
+client.urgent           $fgblack $bginactive $fgred   $fgblack  $fgblack
272
+client.background       $bgnone
... ...
@@ -126,10 +126,14 @@ def watch_windows(sock, changes, handle):
126 126
             handle(sock, {'id': window, **container['window_properties']})
127 127
         for node in nodes:
128 128
             recurse(node)
129
+    # TODO: Race? Subscribe first, handle the `MSG_GET_TREE` response in the
130
+    # `while True`. This is our only use of `sync_reply`, so we could get rid
131
+    # of that if we want.
129 132
     recurse(send(sock, MSG_GET_TREE, sync_reply=True))
130 133
     send(sock, MSG_SUBSCRIBE, ['window', 'shutdown'])
131 134
     while True:
132 135
         tag, msg = recv(sock)
136
+        # TODO: `match`/`case`, requires newer Python.
133 137
         if tag == MSG_SUBSCRIBE:
134 138
             assert msg['success']
135 139
         elif tag == MSG_COMMAND:
... ...
@@ -147,6 +151,7 @@ def replace(sock, props):
147 151
     command(sock, '[id={id}] title_format "{title}"'.format(**props))
148 152
 
149 153
 def restore(sock):
154
+    # TODO: `[all]`, requires newer `i3`.
150 155
     command(sock, '[title=".*"] title_format "%title"')
151 156
 
152 157
 ## Main
... ...
@@ -4,18 +4,28 @@ import sys
4 4
 import subprocess
5 5
 import json
6 6
 
7
-I3_GET    = ['i3-msg', '-t', 'get_workspaces']
8
-I3_RENAME = ['i3-msg', 'rename', 'workspace', 'to']
7
+FILTER        = sys.argv[1:]
8
+I3_WORKSPACES = ['i3-msg', '-t', 'get_workspaces']
9
+I3_RENAME     = ['i3-msg', 'rename', 'workspace', 'to']
10
+ESCAPE        = [
11
+    ['\\', '\\\\'],
12
+    ['"',  '\\"' ],
13
+]
9 14
 
10
-def get():
11
-    for workspace in json.loads(subprocess.check_output(I3_GET)):
15
+def run(*args):
16
+    return subprocess.check_output(args, text=True).strip()
17
+
18
+def name():
19
+    for workspace in json.loads(run(*I3_WORKSPACES)):
12 20
         if workspace['focused']:
13 21
             return workspace['name']
14 22
 
15 23
 def filter(value):
16
-    return subprocess.check_output([*sys.argv[1:], value])
24
+    return run(*FILTER, value)
17 25
 
18 26
 def rename(value):
19
-    subprocess.call([*I3_RENAME, value])
27
+    for old, new in ESCAPE:
28
+        value.replace(old, new)
29
+    run(*I3_RENAME, f'"{value}"')
20 30
 
21
-rename(filter(get()))
31
+rename(filter(name()))
... ...
@@ -1,11 +1,47 @@
1 1
 i3 &
2
-I3_PID="$!"
2
+i3_pid="$!"
3 3
 
4
-while ! [ -e "/run/user/1000/i3/ipc-socket.$I3_PID" ]
4
+# TODO: We still get the error:
5
+#   i3: Could not mkdir(/run/user/1000/i3): File exists
6
+#   i3: Check permissions of $XDG_RUNTIME_DIR = '/run/user/1000'
7
+# sometimes. Look into it. Might be fixed in new version? We often shut down
8
+# with a manual `systemctl poweroff` from within i3 (i.e. while it's still
9
+# running), might that be the problem?
10
+
11
+# Spinlock until `i3` has initialized the IPC socket and set the
12
+# `I3_SOCKET_PATH` property of the X11 root window that other xsession programs
13
+# might require. If `i3` fails for some reason, retrieve its exit code and exit
14
+# ourselves with it.
15
+# <https://i3wm.org/docs/ipc.html>
16
+while ! i3 --get-socketpath > '/dev/null'
5 17
 do
6
-  if ! [ "$(ps -p "$I3_PID" -o pid=)" ]
18
+  # TODO: If the last started background job (`%%`, i.e. `i3 &`) exited (`!
19
+  # jobs %%`) we want to get its exit status (`wait %%`). This seems to not be
20
+  # the way to do it though, since in the case where the job did exit, the
21
+  # `wait %%` gives "wait: No current job". Do some research, it must be
22
+  # possible to get the exit status of the last started job. Would it work to
23
+  # just use `$i3_pid` instead of `%%`?
24
+  if ! jobs %% > '/dev/null' 2>&1
7 25
   then
8
-    wait "$I3_PID"
26
+    wait %%
9 27
     exit $?
10 28
   fi
11 29
 done
30
+
31
+# while ! i3 --get-socketpath > '/dev/null'
32
+# do
33
+#   if ! kill -0 "$i3_pid" > '/dev/null' 2>&1
34
+#   then
35
+#     wait "$i3_pid"
36
+#     exit $?
37
+#   fi
38
+# done
39
+
40
+# while ! [ -e "${XDG_RUNTIME_DIR:-"/run/user/$(id -u)"}/i3/ipc-socket.$i3_pid" ]
41
+# do
42
+#   if ! [ "$(ps -p "$i3_pid" -o pid=)" ]
43
+#   then
44
+#     wait "$i3_pid"
45
+#     exit $?
46
+#   fi
47
+# done
... ...
@@ -1 +1 @@
1
-wait "$I3_PID"
1
+wait "$i3_pid"