Skip to content

Repository files navigation

wlagolap

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 LICENSE for the full BSD 2-Clause terms, which govern.

Why

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-control protocol - 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.

Status

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.

Components

  • 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. Starts wlagolapd if 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).

Build

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 build

Note on libucl: the Debian/Ubuntu package libucl-dev is an unrelated data-compression library of the same name. wlagolap therefore builds the vendored libucl (Universal Configuration Language) by default on Linux. On FreeBSD, install textproc/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).

Debian / Ubuntu package

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 -b

The package is written to the parent directory; install it with:

sudo apt install ../wlagolap_*.deb            # or: sudo dpkg -i ../wlagolap_*.deb

It 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).

Usage

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

Configuration

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.

Global hotkey

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.

Selection semantics

[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

[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.

Privacy

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.

License

BSD 2-Clause. See LICENSE.

Author: Oliver Pinter oliver.pntr@gmail.com.

About

A Wayland clipboard manager that behaves like X. Mostly for sway.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages