112
src/App.cpp
112
src/App.cpp
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user