A Wayland clipboard manager for sway/wlroots that behaves like X11.
The name is wl + Hungarian vágólap ("clipboard").
Disclaimer: This project is fully AI-generated code, produced with Anthropic's Claude (Claude Code). It is written and reviewed with AI assistance; review it accordingly before relying on it in production.
No warranty, no liability. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and non-infringement. In no event shall the authors, copyright holders or sponsor be liable for any claim, damages, data loss or other liability arising from, out of or in connection with the software or its use. You use it entirely at your own risk. See
LICENSEfor the full BSD 2-Clause terms, which govern.
Existing Wayland clipboard managers each solve a slice of the problem and leave
the rest to a pile of wl-copy/wl-paste glue. wlagolap targets the gaps that
matter most:
- X11-parity primary selection. Highlight-to-copy and middle-click paste, a tracked primary-selection history, and content that survives the source app closing (keeper mode) - just like a well-configured X desktop.
- Pick once, paste anywhere. Choosing an item from history places it in the primary selection and the regular clipboard (configurable), so both middle-click and Ctrl+V work.
- One process for everything. A single daemon owns both selections via the
ext-data-control-v1/wlr-data-controlprotocol - no racing helpers. - Proper keybindings and a tray. A hotkey popup picker plus an nm-applet-style system tray icon.
- XWayland-friendly. X clients interoperate through the compositor's selection bridge.
Functional, split into a wlagolapd daemon and a wlagolap-applet GUI. The
architecture is specified in
design/wlagolap-design.md and the phased build
plan in
.claude/plans/wlagolap-implementation-plan.md.
Implemented: the data-control engine (clipboard + primary, keeper), history
store with dedup/media/privacy, optional JSON persistence (optionally
encrypted), sync semantics, UCL/JSON config with a first-run dialog, the IPC
socket with an event channel, the shared client library and wlagolap-ctl, and
the GTK3 tray plus layer-shell popup in the applet.
wlagolapd- the headless daemon: owns both selections, the history store and the IPC socket. No GTK.wlagolap-applet- the GTK front-end: system tray and popup picker, driving the daemon over IPC. Startswlagolapdif it is not already running and owns the first-run setup dialog.wlagolap-ctl- thin CLI client used by compositor keybindings and scripts.
The three share an IPC client library; the daemon is the single owner of all clipboards while the applet is just a UI client (the NetworkManager/nm-applet model).
Requirements: a C11 compiler, CMake >= 3.16, pkg-config, wayland-client,
wayland-scanner, glib-2.0, gio-2.0, gtk+-3.0 and gtk-layer-shell (for
the popup). Optional encryption uses libsodium. The system tray is
implemented directly over GDBus (no appindicator). Configuration/persistence
use libucl (vendored submodule; see the note below).
Configuration and persistence use libucl, vendored as a git submodule and
built statically by default (fetch it once with --recurse-submodules or
git submodule update --init):
./install-deps.sh # Ubuntu/Debian or FreeBSD (--tests for
# optional test/lint tooling)
git submodule update --init # third_party/libucl
cmake -B build
cmake --build build
ctest --test-dir buildNote on libucl: the Debian/Ubuntu package
libucl-devis an unrelated data-compression library of the same name. wlagolap therefore builds the vendored libucl (Universal Configuration Language) by default on Linux. On FreeBSD, installtextproc/libucl(pkg install libucl) and the system copy is used automatically via pkg-config. FreeBSD is a supported target.
Optional CMake flags: -DWLAGOLAP_WITH_TRAY=OFF,
-DWLAGOLAP_WITH_BUILTIN_PICKER=OFF (drop the UI deps),
-DWLAGOLAP_SANITIZE=ON (ASan/UBSan), -DWLAGOLAP_UCL_BUNDLED=ON (force the
vendored libucl).
The repository ships a debian/ directory (a native debhelper + CMake
package). To build a .deb:
sudo apt install build-essential debhelper cmake pkg-config \
libwayland-dev libwayland-bin libglib2.0-dev libgtk-3-dev \
libgtk-layer-shell-dev libsodium-dev
git submodule update --init third_party/libucl # vendored libucl (see note)
dpkg-buildpackage -us -uc -bThe package is written to the parent directory; install it with:
sudo apt install ../wlagolap_*.deb # or: sudo dpkg -i ../wlagolap_*.debIt installs wlagolapd, wlagolap-applet and wlagolap-ctl, their man pages,
the hicolor icons and the config examples. Hardening is delegated to
dpkg-buildflags, and there is deliberately no libucl-dev build
dependency - the vendored submodule is used (see the libucl note above and
debian/README.source).
Start the daemon in your sway session and bind the popup; copy the shipped
snippet from share/wlagolap/sway-wlagolap.conf.example:
exec wlagolap-applet
bindsym $mod+Shift+Ctrl+h exec wlagolap-ctl show-popup
bindsym $mod+Shift+Ctrl+p exec wlagolap-ctl private toggle
On sway the daemon registers the show-popup shortcut itself by default, so you
can omit that bindsym line - see Global hotkey below.
wlagolap-ctl show-popup renders the picker itself, so the popup works with
only the daemon running (no applet/tray needed) - it is the recommended,
keyboard-navigable pick flow. Inside the picker the list has the focus: entries
are numbered from 0, so 0-9 immediately pick that entry; Up/Down move,
Enter applies to the default selection (the configured on_pick, both by
default), Shift+Enter applies to primary only and Ctrl+Enter to
clipboard only (the same Shift/Ctrl modifiers apply to a mouse click);
Left/Right switch the Recent and Pinned tabs, p pins and
u unpins the selection, and s reveals the search box (Escape leaves
search, again closes the popup). The list is most-recently-used ordered:
capturing or picking an entry moves it to the front. Pinned entries survive
eviction and clear and persist across restarts.
The tray icon is a convenience: left-click opens the popup, right-click opens the context menu (recent entries, show clipboard history, private mode, sync, clear, settings, reload configuration, about, Quit applet, and Quit wlagolap which stops the daemon). Keyboard navigation of the tray menu itself is the bar's responsibility on Wayland (waybar etc.), so the popup remains the recommended flow.
wlagolap-ctl drives the running daemon (used by keybindings and scripts):
wlagolap-ctl status
wlagolap-ctl list [--selection clipboard|primary|both] [--limit N]
wlagolap-ctl get <id> # entry content to stdout
wlagolap-ctl copy <id> [--target both|clipboard|primary]
wlagolap-ctl delete <id>
wlagolap-ctl pin <id> # keep: exempt from eviction/clear
wlagolap-ctl unpin <id>
wlagolap-ctl clear [--selection ...]
wlagolap-ctl private [on|off|toggle]
wlagolap-ctl sync <off|primary-to-clipboard|clipboard-to-primary|bidirectional>
wlagolap-ctl show-popup
wlagolap-ctl reload
wlagolap-ctl quit
On first run wlagolap asks a few questions and writes
~/.config/wlagolap/config.json. You may instead write config.ucl (UCL,
nginx-style, with comments and 32mb/150ms-style suffixes); both are parsed
by libucl. See share/wlagolap/config.ucl.example. Apply changes without a
restart with wlagolap-ctl reload.
On sway the daemon registers the popup shortcut for you: at startup it issues a
bindsym <combo> exec wlagolap-ctl show-popup to sway over $SWAYSOCK and an
unbindsym on exit; changing or clearing the combo and reloading
(wlagolap-ctl reload) re-applies it live. This is enabled by default and
configured by
[hotkey]
enable = true # popup hotkey; false to bind it yourself
combo = "Mod4+Ctrl+Shift+h" # sway keybinding syntax
private_enable = false # private-mode toggle hotkey (opt-in)
private_combo = "Mod4+Ctrl+Shift+p" # bound to `wlagolap-ctl private toggle`
(or the "Register global popup hotkey" toggle in the applet settings). The combo
is validated against a strict allowlist before it is sent to sway. A second,
opt-in hotkey (private_enable/private_combo) toggles private mode the same
way. The settings dialog can capture either combo for you: click Record next
to the field and press the key combination (Esc cancels); you can still type a
combo by hand.
If you already bind Mod4+Ctrl+Shift+h (or your chosen combo) in your sway
config, set enable = false (or change the combo) so wlagolap does not take it
over. The feature is sway/wlroots only - on other compositors, or when
$SWAYSOCK is unset, it is a no-op, and you should use the bindsym line from
the snippet above instead.
[sync] mode mirrors external selection changes:
| mode | effect |
|---|---|
off |
primary and clipboard independent (default) |
primary-to-clipboard |
highlighting text also fills the clipboard |
clipboard-to-primary |
Ctrl+C also fills primary |
bidirectional |
keep both identical |
[sync] on_pick controls what picking from history sets: both (default),
clipboard, or primary. Media entries are always clipboard-only and never
land on the primary selection.
[appearance] theme is dark (the default), light, or system to follow the
desktop preference. It selects the matching variant of the active GTK theme for
the popup picker and the GTK dialogs, and is also selectable from the applet's
settings dialog.
Password-manager entries (by MIME hint) and oversized entries are kept in RAM
only and never persisted; media is opt-in and RAM-only. Private mode
(wlagolap-ctl private on, the tray, or the opt-in global hotkey - see
Global hotkey) suspends recording entirely.
When persistence is enabled, the on-disk history can be encrypted at rest by
setting [encryption] enabled = true and a passphrase (libsodium; argon2 key
derivation + authenticated encryption). For now the passphrase is stored in the
config file, so keep it 0600; a system secret store is planned.
BSD 2-Clause. See LICENSE.
Author: Oliver Pinter oliver.pntr@gmail.com.