Files
socktop-swipe/README.md
T

205 lines
8.0 KiB
Markdown
Raw Normal View History

# socktop-swipe
Swipe-to-zoom touchscreen navigation for a wall-mounted
[socktop](https://crates.io/crates/socktop) dashboard.
One tmux window shows every monitored host tiled together. Swiping right-to-left
on the panel zooms into each host full-screen, one at a time; swiping
left-to-right walks back out to the overview.
```
overview -> host 1 -> host 2 -> host 3 -> host 4
(tiled) zoomed zoomed zoomed zoomed
<-------------- swipe left-to-right --------------
```
Built for a 10" touch panel on a server rack driving four Raspberry Pis, on a
low-power x86 box running i3 on X11.
## How it works, and why
**The carousel is tmux pane zoom, not extra socktop instances.** There is exactly
one socktop process per host. Zooming calls `tmux resize-pane -Z`, which makes one
pane fill the window and sends `SIGWINCH` so socktop repaints at the new size.
That matters for three reasons:
- **Half the processes.** Separate full-screen instances would mean N extra
socktop processes and double the polling load on the monitored hosts. On a
1.9 GB display host, that is the difference between comfortable and not.
- **No reconnect delay.** Hidden panes keep running and stay connected, so
swiping back to a host shows current data, not a stale snapshot.
- **Constant load.** The monitored hosts see the same connections regardless of
what is on screen.
**Gestures come from lisgd, below the terminal.** No Linux terminal maps
horizontal swipes to commands, so this cannot be done in terminal config.
Critically, **libinput deliberately emits gesture events only for touchpads,
never for touchscreens** — so `libinput-gestures` and similar tools cannot work
here at all. [lisgd](https://git.sr.ht/~mil/lisgd) reads raw touch events and
synthesises the swipes itself, reading `/dev/input` directly and bypassing X.
## Requirements
- `tmux`, `socktop`, and a working `~/.config/socktop/profiles.json`
- `lisgd` (the installer builds it)
- A C toolchain plus `libinput` and `libX11` headers, to build lisgd
- Membership of the `input` group (the installer adds you; needs a relogin)
## Install
```sh
git clone https://gt.wittyoneoff.com/jason/socktop-swipe
cd socktop-swipe
./install.sh --xignore --i3
```
Then **log out and back in** — the `input` group and the X rule both need a
fresh session.
| Flag | Effect |
| --- | --- |
| *(none)* | Build/install lisgd, install the three scripts and the default config |
| `--xignore` | Also tell X to ignore the touch panel (see below — usually wanted) |
| `--i3` | Also add i3 autostart lines, with a backup and `i3 -C` validation |
Re-running is safe: an existing config file is never overwritten, and the i3
edit is skipped if already present.
### Verify
```sh
tools/find-device.sh # confirm TOUCH_DEV is right
tools/diag.sh # stage 1: device live? stage 2: what does lisgd see?
tools/test-foreground.sh # run the real daemon, watch the display, swipe
```
## Configuration
Everything lives in **`/usr/local/etc/socktop-swipe.env`**. Edit it there, not in
the repo copy. After changing it, restart the daemon and rebuild the session:
```sh
socktop-gestures --replace & # restarts the daemon, running or not
socktop-rack
```
Use `--replace` rather than `pkill -x lisgd && socktop-gestures`: `pkill` exits
non-zero when it matches nothing, so that one-liner silently starts **nothing**
if no daemon was running — you would swipe, get no response, and reasonably
blame the config change.
| Option | Default | What it does |
| --- | --- | --- |
| `SOCKTOP_HOSTS` | four Pi profiles | socktop profile names, **in swipe order**. Any count works; layout and carousel adapt. |
| `SOCKTOP_SESSION` | `socktop4` | tmux session name |
| `SOCKTOP_BIN` | `$HOME/.cargo/bin/socktop` | Full path — i3 does not have `~/.cargo/bin` on `PATH` |
| `TOUCH_DEV` | ILITEK by-id path | Touch device. **Always use a `/dev/input/by-id/` path**; `eventN` numbers change on reboot. |
| `SCREEN_W` / `SCREEN_H` | `1024` / `600` | The **panel's** resolution, not the X screen. See gotcha 2. |
| `SWIPE_THRESHOLD` | `80` | Pixels of travel before a drag counts as a swipe |
| `SWIPE_LENIENCY` | `30` | Degrees off-axis tolerated (max 45) |
| `FINGER_COUNTS` | `1 2 3` | Contact counts accepted. **The setting most likely to need changing** — see gotcha 1. |
| `GESTURE_IN` / `GESTURE_OUT` | `RL` / `LR` | Swap these to reverse swipe direction |
### Adding or removing hosts
Edit `SOCKTOP_HOSTS` and run `socktop-rack`. Nothing else needs touching — the
carousel derives its length from the pane count at runtime.
## Autostart
`./install.sh --i3` appends to `~/.config/i3/config`. For systemd user sessions
instead:
```sh
cp socktop-swipe.service ~/.config/systemd/user/
systemctl --user enable --now socktop-swipe
```
Either way, **run exactly one gesture daemon**. lisgd does not grab the input
device exclusively, so two instances make every swipe fire twice.
`socktop-gestures` enforces this: it exits non-zero if one is already running,
unless given `--replace`.
## Uninstall
```sh
./uninstall.sh # scripts, config, X rule
./uninstall.sh --keep-config # keep your settings
```
lisgd, the `input` group and your socktop profiles are deliberately left alone;
the script prints how to remove each.
## Troubleshooting
Four gotchas account for nearly every failure. All were found the hard way.
### 1. Gestures are recognised but never fire
Run `tools/diag.sh` and read stage 2:
```
[swipe]: Cfg(f=1/s=3/e=0/d=0) <=> Evt(f=2/s=3/e=1/d=2)
^ configured ^ what happened
```
Matching `s=` with differing `f=` means **your panel reports more contacts than
you configured**. Many multipoint panels report 2 or even 3 contacts for a
physically one-finger swipe. Add them to `FINGER_COUNTS`.
Direction enum: `0=DU`, `1=UD`, `2=LR`, `3=RL`.
### 2. Swipes register, but erratically — resizing panes, zooming text
X is also delivering touch to whatever is on screen, so a single swipe hits
several consumers at once: tmux mouse mode drags pane borders, the terminal
reads 2-contact swipes as pinch-zoom, and socktop enables its own all-motion
mouse reporting (`?1003h`). Meanwhile lisgd fires too.
Fix with `./install.sh --xignore` and relog. lisgd is unaffected because it
reads the device directly. Trade-off: no tap or pinch-zoom on that panel —
terminal keyboard zoom (`Ctrl +` / `Ctrl -`) still works.
Also ensure tmux mouse mode is **off**; `socktop-rack` sets this.
### 3. Every swipe jumps two panes
Two lisgd instances are running. `pgrep -x lisgd` should show exactly one.
`socktop-gestures` refuses to start if a daemon is already running, so this
should not happen via the normal path; `--replace` restarts cleanly. It can
still occur if lisgd was launched by hand.
### 4. Swipes do nothing at all
In order: is the session running (`tmux ls`)? Is the daemon running
(`pgrep -x lisgd`)? Does `tools/diag.sh` stage 1 read bytes? Are you in the
`input` group (`id -nG | grep input`, needs a relogin)?
Note lisgd's verbose flag is **`-v`**, not `-D`.
### Multi-monitor note
If the display host has a second monitor, X reports the **combined** root window
(e.g. 2304x720). lisgd would scale its maths to that, so `SCREEN_W`/`SCREEN_H`
must describe the touch panel alone. `socktop-gestures` always passes them
explicitly.
## Known limitations
- **~300 ms repaint on zoom-in.** Between tmux making the pane full-screen and
socktop repainting, you briefly see the old small rendering anchored top-left.
This is socktop's redraw latency, not the gesture path; nothing outside
socktop can fix it. Zooming out has no visible artifact, since panes return to
sizes they were already drawn at.
- Deliberately **no wrap-around** at the ends of the carousel — on a wall display
wrapping makes it impossible to tell where you are.
- X11 only. The lisgd build disables its Wayland backend (`WITHOUT_WAYLAND=1`).
## Tested on
LattePanda (Atom x5-Z8350, 1.9 GB RAM, Cherry Trail graphics), 1024x600 ILITEK
DSI touch panel, Debian 11, i3 on X11, Alacritty 0.16.1, lisgd from git,
monitoring four Raspberry Pis.