Better text input rendering

Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
2025-10-10 15:29:18 +03:00
parent 86024e2c03
commit c4e13985ed
5 changed files with 381 additions and 287 deletions

View File

@@ -319,6 +319,11 @@ auto App::init_wayland() -> void
app->m_kbd.typing.push_back('v');
handled = true;
break;
case XKB_KEY_c:
case XKB_KEY_C:
app->m_kbd.typing.push_back('c');
handled = true;
break;
case XKB_KEY_w:
case XKB_KEY_W:
if (ctrl) {
@@ -530,7 +535,6 @@ auto App::init_wayland() -> void
#endif
};
wl_data_offer_add_listener(offer, &offer_l, app);
// swap old
if (app->m_wayland.curr_offer
&& app->m_wayland.curr_offer != offer)
wl_data_offer_destroy(
@@ -551,45 +555,54 @@ auto App::init_wayland() -> void
app->m_clipboard_cache.clear();
return;
}
char const *mime_utf8 = "text/plain;charset=utf-8";
char const *mime_plain = "text/plain";
char const *mime = "text/plain;charset=utf-8";
int fds[2];
if (pipe(fds) != 0)
return;
wl_data_offer_receive(offer, mime_utf8, fds[1]);
wl_data_offer_receive(offer, mime, fds[1]);
wl_display_flush(app->m_wayland.display);
close(fds[1]);
std::string data_utf8;
char buf[4096];
for (;;) {
ssize_t n = read(fds[0], buf, sizeof(buf));
if (n > 0)
data_utf8.append(buf, buf + n);
else
break;
}
close(fds[0]);
if (data_utf8.empty()) {
if (pipe(fds) != 0)
return;
wl_data_offer_receive(
offer, mime_plain, fds[1]);
wl_display_flush(app->m_wayland.display);
close(fds[1]);
std::string data_plain;
int rfd = fds[0];
std::thread([app, rfd, offer]() {
std::string data;
char buf[4096];
for (;;) {
ssize_t n = read(fds[0], buf, sizeof(buf));
if (n > 0)
data_plain.append(buf, buf + n);
else
break;
ssize_t n = read(rfd, buf, sizeof buf);
if (n > 0) {
data.append(buf, buf + n);
continue;
}
if (n < 0 && errno == EINTR)
continue;
break;
}
close(fds[0]);
app->m_clipboard_cache = std::move(data_plain);
} else {
app->m_clipboard_cache = std::move(data_utf8);
}
close(rfd);
struct Ctx {
App *app;
wl_data_offer *offer;
std::string data;
};
auto *ctx
= new Ctx { app, offer, std::move(data) };
g_main_context_invoke(
nullptr,
+[](gpointer p) -> gboolean {
auto *ctx = static_cast<Ctx *>(p);
if (!ctx->data.empty())
ctx->app->m_clipboard_cache
= std::move(ctx->data);
wl_data_offer_destroy(ctx->offer);
delete ctx;
return G_SOURCE_REMOVE;
},
ctx);
}).detach();
},
};
wl_data_device_add_listener(app->m_wayland.ddev, &ddev_l, app);
@@ -1103,18 +1116,33 @@ auto App::clipboard(std::string_view const &str) -> void
static wl_data_source_listener const src_l = {
.target = [](void *, wl_data_source *, char const *) {},
.send =
[](void *data, wl_data_source *, char const *mime, int32_t fd) {
[](void *data, wl_data_source *, char const *, int32_t fd) {
auto *app = static_cast<App *>(data);
(void)mime;
size_t off = 0;
while (off < app->m_clipboard_cache.size()) {
ssize_t n = write(fd, app->m_clipboard_cache.data() + off,
app->m_clipboard_cache.size() - off);
if (n <= 0)
break;
off += static_cast<size_t>(n);
}
int wfd = dup(fd);
close(fd);
std::pmr::string payload = app->m_clipboard_cache;
std::thread([wfd, payload = std::move(payload)]() {
size_t off = 0;
while (off < payload.size()) {
ssize_t n = write(wfd, payload.data() + off,
std::min<size_t>(64 * 1024, payload.size() - off));
if (n > 0) {
off += (size_t)n;
continue;
}
if (n < 0 && (errno == EINTR))
continue;
if (n < 0 && (errno == EAGAIN)) {
std::this_thread::sleep_for(
std::chrono::milliseconds(1));
continue;
}
break;
}
close(wfd);
}).detach();
},
.cancelled =
[](void *data, wl_data_source *src) {