Clipboard Integration
Connect page copy and paste to the OS or engine by implementing Clipboard.
You can connect copy and paste on the page to an engine's clipboard or the OS clipboard by implementing a Clipboard handler. Clipboard data passes through the handler as whole, multi-format payloads.
The Default Clipboard
App::Create() installs a default handler that connects to the OS clipboard.
Renderer::Create() installs no clipboard handler. A handler is optional— without one, copying on the page does nothing and pasting returns empty.
If you set a clipboard on Platform before calling App::Create() or Renderer::Create(), the renderer uses that handler instead (see Setting Up the Platform).
Clipboard Payloads
Clipboard data is stored in ClipboardData as ordered entries.
Each entry holds text or raw bytes, keyed by a bare MIME type or an application-defined string.
The library reads and writes three standard types: text/plain, text/html, and text/uri-list.
Types must be bare MIME types without parameters (text/plain, rather than text/plain;charset=utf-8).
Building a Payload
To build a payload with multiple formats, call ClipboardData::Create() and chain calls to Set():
#include <Ultralight/Ultralight.h>
using namespace ultralight;
void BuildPayload() {
///
/// Richest format first, then the plain-text version.
///
auto data = ClipboardData::Create();
data->Set("text/html", "<b>Ultralight rocks!</b>")
.Set("text/plain", "Ultralight rocks!");
}
Add the richest format first so the OS clipboard advertises formats in that order.
To create a payload with a single plain-text entry instead, pass the string directly to ClipboardData::Create(text).
Reading a Payload
Call AsText() or AsHTML() to read common text entries directly from a payload. Both methods return an empty string if that format is missing.
To inspect every entry, iterate through the payload using size(), type_at(), and Get() (as shown in the Write() example below).
Implementing a Clipboard
To handle clipboard operations yourself, subclass Clipboard and pass an instance to Platform::instance().set_clipboard().
The interface requires three methods: Read(), Write(), and Clear(). The library does not call Clear(), but you can call it to empty the OS clipboard.
The library calls these methods only on the Renderer's thread, so the implementation does not need to handle concurrent calls from multiple threads.
Handling Pastes
The library calls Read() when a page pastes.
Return a payload containing one entry for each format you can read, providing at least text/plain when the clipboard holds text.
Returning nullptr is equivalent to returning an empty payload— both indicate an empty clipboard.
Whether JavaScript on the page can read the clipboard depends on ViewConfig::clipboard_read_policy (see Text Editing and the Clipboard).
Handling Copies
The library calls Write() when a page copies, replacing the current contents of the clipboard. The passed payload is never null.
Write every supported format in a single OS clipboard transaction so a copy never partially replaces earlier data.
Skip any types you don't recognize— a backend that only supports plain text is fine.
Call source_url() on the payload to get the URL of the document where the copy originated (this may be empty).
Example Implementation
The following implementation reads plain text from the OS clipboard and writes both plain text and HTML using pseudo-code platform calls:
#include <Ultralight/Ultralight.h>
using namespace ultralight;
class MyClipboard : public Clipboard {
public:
void Clear() override {
// Pseudo-code, empty the OS clipboard.
OSClipboardClear();
}
RefPtr<ClipboardData> Read() override {
///
/// We only read text. A null pointer is the same as an empty payload.
///
// Pseudo-code, fetch the OS clipboard's text (empty if there is none).
String text = OSClipboardGetText();
if (text.empty())
return nullptr;
return ClipboardData::Create(text);
}
void Write(RefPtr<ClipboardData> data) override {
///
/// One atomic transaction for the whole payload-- open once, write
/// every entry we support, close once. Unknown types are skipped.
///
// Pseudo-code, open and empty the OS clipboard.
OSClipboardOpen();
for (size_t i = 0; i < data->size(); ++i) {
String type = data->type_at(i);
ClipboardValue value = data->Get(type);
if (type == "text/plain") {
// Pseudo-code, write the OS text format.
OSClipboardSetText(value.text());
} else if (type == "text/html") {
// Pseudo-code, write the OS HTML format (with the page it came from).
OSClipboardSetHTML(value.text(), data->source_url());
}
}
// Pseudo-code, close the OS clipboard.
OSClipboardClose();
}
};
MyClipboard clipboard;
void InitPlatform() {
///
/// Install our clipboard before creating the Renderer. (Ownership
/// stays with us, so 'clipboard' must outlive the Renderer.)
///
Platform::instance().set_clipboard(&clipboard);
}