164
src/App.cpp
164
src/App.cpp
@@ -191,6 +191,8 @@ auto App::run() -> void
|
||||
while (m_running) {
|
||||
pump_events();
|
||||
tick();
|
||||
m_kbd.typing.clear();
|
||||
m_kbd.clear_transients();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
||||
}
|
||||
}
|
||||
@@ -249,19 +251,23 @@ auto App::init_wayland() -> void
|
||||
close(fd);
|
||||
} };
|
||||
|
||||
auto kb_enter { [](void *, wl_keyboard *, u32, wl_surface *,
|
||||
wl_array *) -> void { } };
|
||||
auto kb_enter { [](void *data, wl_keyboard *, u32 serial, wl_surface *,
|
||||
wl_array *) -> void {
|
||||
static_cast<App *>(data)->m_last_serial = serial;
|
||||
} };
|
||||
auto kb_leave
|
||||
= [](void *data, wl_keyboard *, u32, wl_surface *) -> void {
|
||||
static_cast<App *>(data)->m_kbd.held.clear();
|
||||
};
|
||||
|
||||
auto kb_key { [](void *data, wl_keyboard *, u32, u32, u32 key,
|
||||
auto kb_key { [](void *data, wl_keyboard *, u32 serial, u32, u32 key,
|
||||
u32 state) -> void {
|
||||
auto *app { static_cast<App *>(data) };
|
||||
if (!app->m_kbd.xkb_state_v)
|
||||
return;
|
||||
|
||||
app->m_last_serial = serial;
|
||||
|
||||
xkb_keycode_t kc = key + 8;
|
||||
|
||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
@@ -308,6 +314,11 @@ auto App::init_wayland() -> void
|
||||
app->m_kbd.typing.push_back('\n');
|
||||
handled = true;
|
||||
break;
|
||||
case XKB_KEY_v:
|
||||
case XKB_KEY_V:
|
||||
app->m_kbd.typing.push_back('v');
|
||||
handled = true;
|
||||
break;
|
||||
case XKB_KEY_w:
|
||||
case XKB_KEY_W:
|
||||
if (ctrl) {
|
||||
@@ -490,6 +501,99 @@ auto App::init_wayland() -> void
|
||||
registry, name, &zwp_text_input_manager_v3_interface, 1));
|
||||
app->m_ime.supported = true;
|
||||
ensure_text_input(app);
|
||||
} else if (std::strcmp(interface, wl_data_device_manager_interface.name)
|
||||
== 0) {
|
||||
app->m_wayland.ddm
|
||||
= static_cast<wl_data_device_manager *>(wl_registry_bind(
|
||||
registry, name, &wl_data_device_manager_interface,
|
||||
std::min<uint32_t>(version, 3)));
|
||||
if (app->m_wayland.ddm && !app->m_wayland.ddev) {
|
||||
app->m_wayland.ddev = wl_data_device_manager_get_data_device(
|
||||
app->m_wayland.ddm, app->m_wayland.seat);
|
||||
static wl_data_device_listener const ddev_l = {
|
||||
.data_offer =
|
||||
[](void *data, wl_data_device *, wl_data_offer *offer) {
|
||||
auto *app = static_cast<App *>(data);
|
||||
static wl_data_offer_listener const offer_l = {
|
||||
.offer =
|
||||
[](void *data, wl_data_offer *,
|
||||
char const *mime) {
|
||||
auto *app = static_cast<App *>(data);
|
||||
(void)app;
|
||||
(void)mime;
|
||||
},
|
||||
#if WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION
|
||||
.source_actions
|
||||
= [](void *, wl_data_offer *, uint32_t) {},
|
||||
.action
|
||||
= [](void *, wl_data_offer *, uint32_t) {}
|
||||
#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(
|
||||
app->m_wayland.curr_offer);
|
||||
app->m_wayland.curr_offer = offer;
|
||||
},
|
||||
.enter
|
||||
= [](void *, wl_data_device *, uint32_t, wl_surface *,
|
||||
wl_fixed_t, wl_fixed_t, wl_data_offer *) {},
|
||||
.leave = [](void *, wl_data_device *) {},
|
||||
.motion = [](void *, wl_data_device *, uint32_t, wl_fixed_t,
|
||||
wl_fixed_t) {},
|
||||
.drop = [](void *, wl_data_device *) {},
|
||||
.selection =
|
||||
[](void *data, wl_data_device *, wl_data_offer *offer) {
|
||||
auto *app = static_cast<App *>(data);
|
||||
if (!offer) {
|
||||
app->m_clipboard_cache.clear();
|
||||
return;
|
||||
}
|
||||
char const *mime_utf8 = "text/plain;charset=utf-8";
|
||||
char const *mime_plain = "text/plain";
|
||||
int fds[2];
|
||||
if (pipe(fds) != 0)
|
||||
return;
|
||||
wl_data_offer_receive(offer, mime_utf8, 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;
|
||||
for (;;) {
|
||||
ssize_t n = read(fds[0], buf, sizeof(buf));
|
||||
if (n > 0)
|
||||
data_plain.append(buf, buf + n);
|
||||
else
|
||||
break;
|
||||
}
|
||||
close(fds[0]);
|
||||
app->m_clipboard_cache = std::move(data_plain);
|
||||
} else {
|
||||
app->m_clipboard_cache = std::move(data_utf8);
|
||||
}
|
||||
},
|
||||
};
|
||||
wl_data_device_add_listener(app->m_wayland.ddev, &ddev_l, app);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -981,3 +1085,57 @@ auto App::pump_events() -> void
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto App::clipboard(std::string_view const &str) -> void
|
||||
{
|
||||
if (!m_wayland.ddm || !m_wayland.ddev || !m_wayland.seat)
|
||||
return;
|
||||
if (m_last_serial == 0)
|
||||
return;
|
||||
|
||||
if (m_wayland.curr_source) {
|
||||
wl_data_source_destroy(m_wayland.curr_source);
|
||||
m_wayland.curr_source = nullptr;
|
||||
}
|
||||
m_wayland.curr_source
|
||||
= wl_data_device_manager_create_data_source(m_wayland.ddm);
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
close(fd);
|
||||
},
|
||||
.cancelled =
|
||||
[](void *data, wl_data_source *src) {
|
||||
auto *app = static_cast<App *>(data);
|
||||
if (app->m_wayland.curr_source == src)
|
||||
app->m_wayland.curr_source = nullptr;
|
||||
wl_data_source_destroy(src);
|
||||
},
|
||||
#if WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION
|
||||
.dnd_drop_performed = [](void *, wl_data_source *) {},
|
||||
.dnd_finished = [](void *, wl_data_source *) {},
|
||||
.action = [](void *, wl_data_source *, uint32_t) {}
|
||||
#endif
|
||||
};
|
||||
wl_data_source_add_listener(m_wayland.curr_source, &src_l, this);
|
||||
wl_data_source_offer(m_wayland.curr_source, "text/plain;charset=utf-8");
|
||||
wl_data_source_offer(m_wayland.curr_source, "text/plain");
|
||||
|
||||
m_clipboard_cache.assign(str.begin(), str.end());
|
||||
|
||||
wl_data_device_set_selection(
|
||||
m_wayland.ddev, m_wayland.curr_source, m_last_serial);
|
||||
wl_display_flush(m_wayland.display);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user