Skip to content

Commit 8fe46b2

Browse files
committed
Commit working version
1 parent 9f3d3bb commit 8fe46b2

File tree

5 files changed

+263
-1
lines changed

5 files changed

+263
-1
lines changed

README.md

Lines changed: 173 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,174 @@
11
# i3-focus.sh
2-
i3wm focus mode (sh version)
2+
3+
<img alt="i3-focus.sh" width="800"
4+
src="media/screenshot.png">
5+
6+
## i3wm focus mode (sh version)
7+
8+
I recently stumbled upon an [interesting](https://www.reddit.com/r/i3wm/comments/eqzq1d/need_to_focus_try_i3quiet_mode/) [project](https://github.com/vrde/i3-quiet). It is implemented in [Python](https://www.python.org/) and what it does is to offer a distraction free [i3 wm](https://i3wm.org/) experience. Even if not completely new subject, it reads very good!
9+
10+
I was then intrigued and wanted to check if/how I could implement it with plain `sh` script.
11+
12+
Turns out that it is possible (!) and not too difficult (!!): the most time consuming part has been to find why [jq](https://stedolan.github.io/jq) behaved weirdly. Hint: I did not thoroughly `RTFM` (!?!).
13+
14+
Anyway, check the [known issues](#known-issues).
15+
16+
Even if this is a personal project (and it works already well for my needs), since it is publicly hosted I declare it open sourced (with a nice license).
17+
18+
Anyway: suggestions, tips, help, etc are welcome.
19+
20+
### Rational
21+
22+
I had a few constraints in mind. The implementation should:
23+
24+
- be relatively POSIX compliant (`#!/usr/bin/env bash`)
25+
- have [jq](https://stedolan.github.io/jq) as, eventual, only dependency
26+
- need only one [key binding](#i3wm-configuration)
27+
28+
Personally I use `zsh`, but I chose `bash` because `sh` generally is a `depends on os` soft or hard link to some other shell including `bash` itself, `dash`, `pdksh`, etc and a few more reasons.
29+
30+
In this way, the script should behave consistently on every system having `bash` installed.
31+
32+
Also, when leaving focus workspace without exiting focus mode (switching to another workspace/output as usual), the bar should:
33+
34+
- automatically and temporarily be [restored](#polybar-module) as [option](#polybar-configuration)
35+
- automatically be [hidden](#polybar-module) when switching back to focus workspace/output
36+
- automatically and definitely [restored](#polybar-module) when leaving quiet mode
37+
38+
About the focusd window, it should:
39+
40+
- be restored to the original workspace, even if it does not exist anymore (window was the only one in original workspace)
41+
- be restored to the correct workspace, even if it uses strange/weird names
42+
- this, hopefully, works
43+
44+
Again, to enter/exit quiet mode, to switch from/to focus worksapce should need only one [key binding](#i3wm-configuration).
45+
46+
### i3wm configuration
47+
48+
Only configuration needed on [i3 wm](https://i3wm.org/) side is to add a keybinding in `/path/to/.i3/config`. For example:
49+
50+
```sh
51+
# quiet mode
52+
bindsym $mod+q exec $HOME/dotfiles/bin/i3wm-focus
53+
```
54+
That's all, folks!
55+
56+
Almost all. I do not use borders, if needed, add:
57+
58+
- in `enable_focus_mode()`
59+
60+
```sh
61+
i3-msg border none
62+
```
63+
64+
- in `disable_focus_mode()`
65+
66+
```sh
67+
i3-msg border normal
68+
```
69+
70+
### Polybar configuration
71+
72+
#### Polybar IPC
73+
74+
There are two supported way to automatically show/hide the bar depending if focus mode is or not enabled.
75+
76+
The first and more verbose requires a module in Polybar config.
77+
78+
- enable [inter-process messaging](https://github.com/polybar/polybar/wiki/Inter-process-messaging)
79+
80+
```sh
81+
enable-ipc = true
82+
```
83+
in `/path/to/polybar/config` (needed to manage bar state with `polybar-msg cmd show/hide`)
84+
85+
#### Polybar module
86+
87+
```sh
88+
[module/i3-quiet]
89+
type=custom/script
90+
exec=$HOME/dotfiles/bin/i3wm-quiet-polybar
91+
format=<label>
92+
format-background=#282a36
93+
format-foreground=#e6e6e6
94+
label=
95+
tail=true
96+
```
97+
This module can be further stripped down. For example, no need for a visual clue in the bar to work.
98+
With this configuration, the following behavior is offered:
99+
100+
- bar is automatically hidden when entering quiet mode
101+
- switching out of focused workspace without exiting focus mode (switching to another workspace/output as usual):
102+
- bar is automatically and temporarily [restored](#polybar-module)
103+
- switching back to focus workspace/output automatically [hides](#polybar-module) again the bar
104+
- bar is automatically restored when exiting focus mode
105+
106+
This method introduces a noticeable lag.
107+
108+
The second, simpler, way:
109+
110+
- solves the lag [known issue](#known-issues)
111+
- but when switching to another workspace/output as usual, the bar is not automatically and temporarily restored (only restores the bar when exiting focus mode)
112+
113+
I use the second alternative: much lighter and fast.
114+
115+
A third alternative could be to activate focus mode when launching a specific application, as a PDF viewer.
116+
117+
### Output configuration
118+
119+
At the moment the support is very primitive and, most likely, will remain this way (unless offered `PR` will manage it thoroughly).
120+
121+
To configure it, in `i3wm-quiet`:
122+
123+
- in `enable_focus_mode()`, add one of the following example lines:
124+
125+
```sh
126+
# Primitive output support
127+
#i3-msg move container to output "HDMI-1"
128+
#i3-msg move workspace to output right
129+
```
130+
131+
- in `disable_focus_mode()`
132+
133+
```sh
134+
# Primitive output support
135+
#i3-msg move workspace to output left
136+
```
137+
138+
Adapt them to the personal configuration.
139+
140+
### Dependencies
141+
142+
[jq](https://stedolan.github.io/jq)
143+
144+
### Known issues
145+
146+
- to manage the bar
147+
- first method: using [Polybar module](#polybar-module) introduces a noticeable lag
148+
- second method: to use `polybar-msg cmd toggle` directly in `i3wm-focus` is very quick, but
149+
- to maintain the script simple, the bar is restored only leaving focus mode
150+
151+
- very primitive outputs support
152+
- when the [output](#output-configuration) support is enabled and the focus workspace is then moved to another output
153+
- when leaving focus mode
154+
- the focus workspace is not automatically closed
155+
- /shrug
156+
157+
- when exiting focus mode, the window does not automatically goes back to original stack position. To restore an i3 [layout](https://i3wm.org/docs/layout-saving.html) is not straightforward and not a priority for this project (unless a `PR` will do it).
158+
159+
- unable to split the script in proper script file + configuration file:
160+
- works from terminal
161+
- completely ignored when using key binding
162+
163+
- a temp file (`/tmp/i3-focus.tmp`) holds the original workspace name
164+
165+
- yes, screenshot taken with scrot...
166+
167+
### Inspiration
168+
169+
[vrde/i3-quiet](https://github.com/vrde/i3-quiet)
170+
171+
### TODO
172+
173+
- some ideas, but this is still an experiment
174+
- to be ble to split the script in proper script file + configuration file would be a nice thing

i3wm-focus

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env bash
2+
3+
# https://github.com/maxdevjs/i3-focus.sh
4+
5+
focus_number="99"
6+
width_perc="50"
7+
max_width="800"
8+
height_perc="90"
9+
max_height="1024"
10+
11+
enable_focus_mode() {
12+
w=$(( $2 * width_perc / 100 ))
13+
h=$(( $3 * height_perc / 100 ))
14+
wu=$(( w < max_width ? w : max_width ))
15+
hu=$(( h < max_height ? h : max_height ))
16+
17+
workspace_focus_name=$"${focus_number}:${1}"
18+
19+
i3-msg "move container to workspace \"${workspace_focus_name}\" workspace \"${workspace_focus_name}\" floating enable"
20+
i3-msg resize set width "${wu}" && i3-msg resize set height "${hu}" && i3-msg move position center
21+
22+
# Simple Polybar support
23+
polybar-msg cmd toggle
24+
}
25+
26+
disable_focus_mode() {
27+
workspace_original_name=$(</tmp/i3-focus.tmp)
28+
i3-msg "move container to workspace \"${workspace_original_name}\" workspace \"${workspace_original_name}\" floating disable"
29+
rm /tmp/i3-focus.tmp
30+
31+
# Simple Polybar support
32+
polybar-msg cmd toggle
33+
}
34+
35+
main() {
36+
workspace_current_name=$(i3-msg -t get_workspaces | jq -r '.[] | select(.focused==true).name')
37+
if [[ $workspace_current_name =~ "99" ]]
38+
then
39+
# Already focused. Going to exit from this state
40+
disable_focus_mode
41+
else
42+
# Out of focus, going back to it
43+
workspaces=$(i3-msg -t get_workspaces)
44+
workspace_current_num=$(i3-msg -t get_workspaces | jq -r '.[] | select(.focused==true).num')
45+
if [[ ! $workspace_current_num =~ "99" && $workspaces =~ "99" ]]
46+
then
47+
workspace_focus_name=$(i3-msg -t get_workspaces | jq -r '.[] | select(.num==99).name')
48+
i3-msg workspace $workspace_focus_name
49+
else
50+
# Activating focus
51+
workspace_original_name=$(i3-msg -t get_workspaces | jq -r '.[] | select(.focused==true).name')
52+
echo $workspace_original_name > /tmp/i3-focus.tmp
53+
enable_focus_mode \
54+
$(i3-msg -t get_workspaces | jq -r '.[] | select(.focused==true).name') \
55+
$(i3-msg -t get_workspaces | jq -r '.[] | select(.focused==true).rect.width') \
56+
$(i3-msg -t get_workspaces | jq -r '.[] | select(.focused==true).rect.height')
57+
fi
58+
fi
59+
}
60+
61+
main
62+
63+
64+
65+
66+
67+
68+

i3wm-focus-polybar

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env bash
2+
3+
# https://github.com/maxdevjs/i3-focus.sh
4+
5+
main() {
6+
workspace_current_name=$(i3-msg -t get_workspaces | jq -r '.[] | select(.focused==true).name')
7+
if [[ $workspace_current_name =~ "99" ]]
8+
then
9+
$(polybar-msg cmd hide)
10+
else
11+
$(polybar-msg cmd show)
12+
fi
13+
}
14+
15+
main
16+
17+
18+
19+
20+
21+
22+

media/enso-zen.png

1.31 MB
Loading

media/screenshot.png

1.35 MB
Loading

0 commit comments

Comments
 (0)