---
title: Keeping the clipboard alive
date: 2024-09-04
tags: [design, wayland]
description: Copied data is lost when you close the application that you wanted to copy from. I find this deeply confusing. I believe we can do better.
---

It frequently happens to me that I want to paste something, but nothing
happens. This is because on wayland (and many other systems, but I will
focus on wayland) the copied data is lost when you close the application
that you wanted to copy from. I find this deeply confusing. The official
solution seems to be to setup a clipboard manager. However, I found out
that clipboard managers are not a solution, they just make different
trade offs. I believe we can do better.

## The Problem

I first thought that the clipboard contains the actual bits that are
being copied. But that is not the case. When you hit Ctrl-C, no data is
actually copied. Instead the data can be offered in multiple mime types
at the same time, so that the receiving end can pick which mime type it
prefers. For example, text copied from the web browser could be offered
as both `text/html` and `text/plain`.

Of course, this mechanism only works as long as the application that is
offering the data does not quit. After that, there is no one left to
answer the request.

## Clipboard managers

A common workaround for that problem is to use a clipboard manager like
this:

    wl-paste --watch cliphist store

In this case, `wl-paste` will call `cliphist store` whenever something
is copied. It passes the copied data in one of the available mime types.
`cliphist` will then replace the original offer with its own
(`text/plain`). This means that the clipboard contents will not be lost
when the original source goes away. But it also has some drawbacks:

-   Most mime type information is lost
-   The data needs to be transferred even if it is never actually pasted

[`clipmon`](https://git.sr.ht/~whynothugo/clipmon) is another clipboard
manager that makes slightly different trade offs: It also replaces the
original offer with its own, but it preserves all mime types. This
solves the first drawback, but amplifies the second one: the same image
might have to be stored in multiple different formats. The author of
`clipmon` wrote a [great blog post about these trade
offs](https://whynothugo.nl/journal/2022/10/21/how-the-clipboard-works/).

So in summary, the following goals are in conflict:

-   offer content in different mime types
-   keep the clipboard alive when an application quits
-   avoid unnecessary data transfer and storage

## Finding balance

Many clipboard managers have features beyond just keeping the clipboard
alive. But I only care about find a better default behavior.

It would be nice if we could keep the original offer intact, and only
replace it with a fallback if the application actually quits. The
fallback could be restricted (e.g. only offer `text/plain`) to avoid
wasting resources. Still, I think this would be a more balanced solution
than what is currently available.

I came up with the following script which can be used with
`wl-paste --watch`:

``` sh
#!/bin/sh -e
path="/tmp/clipboard-$USER-$XDG_SEAT.txt"
input=$(cat)

if [ -n "$input" ]; then
    umask 077
    printf '%s' "$input" > "$path"
elif [ -f "$path" ] && ! wl-paste -l >/dev/null 2>&1; then
    wl-copy < "$path"
fi
```

## Moving it into the compositor

I think the behavior I described above should be implemented in
compositors for three reasons:

-   It should be the default behavior

-   The above script has a race condition if an application creates a
    new offer right before the call to `wl-copy`. Compositors have more
    information and might be able to avoid that (not sure about it, this
    might be an issue on the protocol level).

-   By default, the wayland protocol only allows the currently active
    window to access the clipboard for security reasons. Clipboard
    managers only work if the compositor supports the [wlr data
    control](https://wayland.app/protocols/wlr-data-control-unstable-v1)
    extension protocol. Not relying on that protocol is the more secure
    option.

*Much of this post is based on discussions in
<https://github.com/labwc/labwc/issues/2042>.*
