mesh/merge-gate out of date: judged against trunk aee97bf8ad42, the trunk is now 7443938fef69; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk aee97bf8ad42, the trunk is now 7443938fef69; judged again on a recheck or when it is merged
mesh/delivery superseded: a newer head of the same pull request
clipmenud is declared as the operator's user unit, enabled and running, with a launcher that finds the display. Copy reads the clipboard back and fails with the reason. History and paste answer counts, times and lengths, never content.
96 lines
6.1 KiB
Markdown
96 lines
6.1 KiB
Markdown
# clipmenu
|
|
|
|
The clipboard manager as a module (novox/hq ADR 0208, research 026/04).
|
|
|
|
- Installs `clipmenu` from the official repositories. It brings `clipnotify`, `xsel`, `xdotool` and
|
|
`dmenu` as its own dependencies.
|
|
- Claims the mesh's `node-clipboard` seat and serves its verbs `history` and `copy`. Requires
|
|
`x11-display` on its own machine.
|
|
- **Declares `rofi-greenclip` absent** (ADR 0180). This module replaces it.
|
|
- Declares `clipmenud.service` as a **user unit of the operator's account**, enabled and running
|
|
(`scope: user`, ADR 0177; issue 743), so `$mod+.` shows the history again. It is the only starter: the
|
|
session's `xinitrc` line is gone. A drop-in (`~/.config/systemd/user/clipmenud.service.d/mesh.conf`)
|
|
replaces `ExecStart` with the module's launcher, which finds the X display from its socket (the account's
|
|
service manager has no `DISPLAY`) and puts the text-only `xsel` first on the `PATH`; until the display is up
|
|
it waits (a quick exit would run into the start limit, which the drop-in also switches off, with `RestartSec=2s`). `DISPLAY` and `XAUTHORITY` come from the user manager when the session's xinitrc has handed them over (module xorg); with several X servers and no `DISPLAY` yet, it waits for them. The store is in the account's runtime directory (mode 0700),
|
|
so no other account reads it.
|
|
**After delivery the operator logs in again**: the running session keeps the `clipmenud` its xinitrc
|
|
started, and the new unit waits on clipmenud's session lock until that one ends.
|
|
- Binds `$mod+period` to `clipmenu`, as its own i3 drop-in (`50-clipmenu.conf`). clipmenu shows the
|
|
history through `dmenu`, the seat command of `node-launcher`, so it looks like every other menu.
|
|
- Its settings are environment contributions (ADR 0203), read by the daemon, the menu and the tools
|
|
alike:
|
|
- `CM_SELECTIONS=clipboard`: what was copied, not every highlighted word. The found greenclip did
|
|
the same.
|
|
- `CM_MAX_CLIPS=500`: how many clips are kept.
|
|
- `CM_HISTLENGTH=15`: how many lines the menu shows.
|
|
|
|
## Tools
|
|
|
|
| tool | does |
|
|
|---|---|
|
|
| `node-clipboard.history` | the history, newest first: count, time and length of each entry, and whether the daemon collects. **Never a text, a first line or an id** (issue 750); the text is read through clipmenu on the operator's own screen |
|
|
| `node-clipboard.copy` | put text on the clipboard, then read it back; an error with the reason (no `DISPLAY`, `xsel` exited, other contents) when it does not hold the text. It enters the history like any copy |
|
|
| `clipmenu_paste` | how many bytes of text the clipboard holds now, never the text |
|
|
| `clipmenu_clear` | forget the history; the daemon's locks stay |
|
|
| `clipmenu_delete` | forget one entry, by its place in the history (1 is the newest) and the time the history gave it, refused if the history changed since; not by text or id |
|
|
|
|
The history is read from clipmenu's own store, in the account's runtime directory, under clipmenu's
|
|
own lock, so a copy arriving meanwhile is neither lost nor half-written. `copy` hands the text to an
|
|
owner (`xsel`) under the account's service manager. As a child of the tools runtime, the clipboard
|
|
would empty whenever the runtime restarted.
|
|
|
|
## What it improves on what was found
|
|
|
|
- **No AUR package.** greenclip came from the user repository. clipmenu is in the official one.
|
|
- **Started once.** greenclip was started by the window manager on both workstations, and on the
|
|
desktop by an enabled user unit as well.
|
|
- **No absolute home path** in any configuration. greenclip's named one.
|
|
- **The history does not outlive a reboot.** greenclip kept it in `~/.cache`, so every password ever
|
|
copied stayed on disk. clipmenu keeps it in the runtime directory, which is memory.
|
|
- **One menu.** The history appears in the launcher's own menu, through the seat's `dmenu` command,
|
|
instead of a theme from a cloned theme repository.
|
|
|
|
## What it leaves as found
|
|
|
|
- `~/.config/greenclip.toml` and greenclip's history, `~/.cache/greenclip.history`.
|
|
- On the desktop: greenclip's enabled user unit link
|
|
(`~/.config/systemd/user/default.target.wants/greenclip.service`). It dangles once the package is
|
|
gone.
|
|
|
|
## Migration (ADR 0182)
|
|
|
|
1. After the first push, delete `~/.config/greenclip.toml` and `~/.cache/greenclip.history`.
|
|
2. On the desktop: `systemctl --user disable greenclip.service`, before the push if you can. The
|
|
package's removal takes the unit file with it.
|
|
3. Until the `i3` module carries the main configuration, the found `exec --no-startup-id greenclip
|
|
daemon` and `$mod+period` lines stay in `~/.config/i3/config`. i3 reports `$mod+period` as bound
|
|
twice. The `i3` module's configuration carries neither.
|
|
|
|
## Blockers
|
|
|
|
- `node-clipboard`, `x11-display` and the `xinitrc` slot are ADR 0208's. Until the controller knows
|
|
them, `mctl` reads them as unknown.
|
|
- `CM_*` reach the session through `node-env` (ADR 0203), so the account's environment module must
|
|
be assigned too. Without it clipmenu runs on its defaults: both selections, 1000 clips, 8 lines.
|
|
|
|
## Only text is read (added 2026-10-04)
|
|
|
|
clipmenud reads a selection with `timeout 1 xsel -o`. A selection holding an image, such as a
|
|
screenshot copied as `image/png`, arrives in pieces. One second is too short for megabytes, so
|
|
`timeout` kills xsel half way, and the program owning the image waits for ever for a reader that is
|
|
gone. From then on every paste hangs, and an app asking on its main thread (Electron: Slack) freezes.
|
|
The first screenshot after this module was assigned did exactly that.
|
|
|
|
So clipmenud runs with the module's own `xsel` first on its `PATH`
|
|
(`/usr/local/lib/mesh-clipmenu/xsel`). Before a read it asks the selection for its `TARGETS` and goes
|
|
ahead only when the selection offers text. It uses `xclip` for that question, which the `xclip`
|
|
module installs on every workstation.
|
|
|
|
## Its i3 lines are a contribution (changed 2026-10-05, novox/hq ADR 0212)
|
|
|
|
The module no longer writes a file into i3's `config.d`. Its window-manager lines (the source is still
|
|
under `files/i3/` where it had one) are a contribution to `node-display-session`. The i3 module places
|
|
them in its own configuration under a `# <module>` line, so this module depends on a window manager
|
|
being assigned beside it.
|