2024-08-30 14:53:25 +00:00
|
|
|
/*
|
2024-09-17 19:00:25 +00:00
|
|
|
* Deskflow -- mouse and keyboard sharing utility
|
2025-01-27 07:33:18 +00:00
|
|
|
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
2025-01-24 00:11:17 +00:00
|
|
|
* SPDX-FileCopyrightText: (C) 2024 Symless Ltd.
|
|
|
|
|
* SPDX-FileCopyrightText: (C) 2022 Red Hat, Inc.
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
2024-08-30 14:53:25 +00:00
|
|
|
*/
|
|
|
|
|
|
2024-10-21 20:39:15 +00:00
|
|
|
#include "platform/PortalInputCapture.h"
|
2024-08-30 14:53:25 +00:00
|
|
|
#include "base/Event.h"
|
|
|
|
|
#include "base/Log.h"
|
|
|
|
|
#include "base/TMethodJob.h"
|
|
|
|
|
|
|
|
|
|
#include <sys/socket.h> // for EIS fd hack, remove
|
|
|
|
|
#include <sys/un.h> // for EIS fd hack, remove
|
|
|
|
|
|
2024-09-17 19:00:25 +00:00
|
|
|
namespace deskflow {
|
2024-08-30 14:53:25 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
enum signals
|
|
|
|
|
{
|
2024-08-30 14:53:25 +00:00
|
|
|
SESSION_CLOSED,
|
|
|
|
|
DISABLED,
|
|
|
|
|
ACTIVATED,
|
|
|
|
|
DEACTIVATED,
|
|
|
|
|
ZONES_CHANGED,
|
|
|
|
|
_N_SIGNALS,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PortalInputCapture::PortalInputCapture(EiScreen *screen, IEventQueue *events)
|
2025-06-20 00:49:53 +00:00
|
|
|
: m_screen{screen},
|
|
|
|
|
m_events{events},
|
|
|
|
|
m_portal{xdp_portal_new()},
|
|
|
|
|
m_signals{_N_SIGNALS}
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-06-20 00:49:53 +00:00
|
|
|
m_glibMainLoop = g_main_loop_new(nullptr, true);
|
|
|
|
|
m_glibThread = new Thread(new TMethodJob<PortalInputCapture>(this, &PortalInputCapture::glibThread));
|
2024-08-30 14:53:25 +00:00
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
auto init_capture_cb = [](gpointer data) { return static_cast<PortalInputCapture *>(data)->initSession(); };
|
2024-08-30 14:53:25 +00:00
|
|
|
|
|
|
|
|
g_idle_add(init_capture_cb, this);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
PortalInputCapture::~PortalInputCapture()
|
|
|
|
|
{
|
2025-06-20 00:49:53 +00:00
|
|
|
if (g_main_loop_is_running(m_glibMainLoop))
|
|
|
|
|
g_main_loop_quit(m_glibMainLoop);
|
2024-08-30 14:53:25 +00:00
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
if (m_glibThread) {
|
|
|
|
|
m_glibThread->cancel();
|
|
|
|
|
m_glibThread->wait();
|
|
|
|
|
m_glibThread = nullptr;
|
2024-08-30 14:53:25 +00:00
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
g_main_loop_unref(m_glibMainLoop);
|
|
|
|
|
m_glibMainLoop = nullptr;
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
if (m_session) {
|
|
|
|
|
XdpSession *parent_session = xdp_input_capture_session_get_session(m_session);
|
|
|
|
|
g_signal_handler_disconnect(G_OBJECT(parent_session), m_signals[SESSION_CLOSED]);
|
|
|
|
|
g_signal_handler_disconnect(m_session, m_signals[DISABLED]);
|
|
|
|
|
g_signal_handler_disconnect(m_session, m_signals[ACTIVATED]);
|
|
|
|
|
g_signal_handler_disconnect(m_session, m_signals[DEACTIVATED]);
|
|
|
|
|
g_signal_handler_disconnect(m_session, m_signals[ZONES_CHANGED]);
|
|
|
|
|
g_object_unref(m_session);
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
for (auto b : m_barriers) {
|
2024-08-30 14:53:25 +00:00
|
|
|
g_object_unref(b);
|
|
|
|
|
}
|
2025-06-20 00:49:53 +00:00
|
|
|
m_barriers.clear();
|
|
|
|
|
g_object_unref(m_portal);
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
gboolean PortalInputCapture::timeoutHandler() const
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-08-30 14:53:25 +00:00
|
|
|
return true; // keep re-triggering
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
int PortalInputCapture::fakeEisFd() const
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-08-30 14:53:25 +00:00
|
|
|
auto path = std::getenv("LIBEI_SOCKET");
|
|
|
|
|
|
|
|
|
|
if (!path) {
|
|
|
|
|
LOG_DEBUG("cannot fake eis socket, env var not set: LIBEI_SOCKET");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto sock = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
|
|
|
|
|
|
|
|
|
// Dealing with the socket directly because nothing in lib/... supports
|
|
|
|
|
// AF_UNIX and I'm too lazy to fix all this for a temporary hack
|
|
|
|
|
int fd = sock;
|
|
|
|
|
struct sockaddr_un addr = {
|
|
|
|
|
.sun_family = AF_UNIX,
|
|
|
|
|
.sun_path = {0},
|
|
|
|
|
};
|
|
|
|
|
std::snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
|
|
|
|
|
|
2025-05-02 12:03:44 +00:00
|
|
|
if (auto result = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); result != 0) {
|
2024-08-30 14:53:25 +00:00
|
|
|
LOG_DEBUG("faked eis fd failed: %s", strerror(errno));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sock;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
void PortalInputCapture::handleSessionClosed(XdpSession *session)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-08-30 14:53:25 +00:00
|
|
|
LOG_ERR("portal input capture session was closed, exiting");
|
2025-06-20 00:49:53 +00:00
|
|
|
g_main_loop_quit(m_glibMainLoop);
|
|
|
|
|
m_events->addEvent(EventTypes::Quit);
|
2024-08-30 14:53:25 +00:00
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
g_signal_handler_disconnect(session, m_signals[SESSION_CLOSED]);
|
|
|
|
|
m_signals[SESSION_CLOSED] = 0;
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
void PortalInputCapture::handleInitSession(GObject *object, GAsyncResult *res)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-09-09 10:18:17 +00:00
|
|
|
LOG_DEBUG("portal input capture session initialized");
|
2024-08-30 14:53:25 +00:00
|
|
|
g_autoptr(GError) error = nullptr;
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
auto session = xdp_portal_create_input_capture_session_finish(XDP_PORTAL(object), res, &error);
|
2024-08-30 14:53:25 +00:00
|
|
|
if (!session) {
|
2024-10-17 18:04:35 +00:00
|
|
|
LOG_ERR("failed to initialize input capture session, quitting: %s", error->message);
|
2025-06-20 00:49:53 +00:00
|
|
|
g_main_loop_quit(m_glibMainLoop);
|
|
|
|
|
m_events->addEvent(EventTypes::Quit);
|
2024-08-30 14:53:25 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
m_session = session;
|
2024-08-30 14:53:25 +00:00
|
|
|
|
|
|
|
|
auto fd = xdp_input_capture_session_connect_to_eis(session, &error);
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
LOG_ERR("failed to connect to eis: %s", error->message);
|
|
|
|
|
|
|
|
|
|
// FIXME: Development hack to avoid having to assemble all parts just for
|
|
|
|
|
// testing this code.
|
2025-06-20 00:49:53 +00:00
|
|
|
fd = fakeEisFd();
|
2024-08-30 14:53:25 +00:00
|
|
|
|
|
|
|
|
if (fd < 0) {
|
2025-06-20 00:49:53 +00:00
|
|
|
g_main_loop_quit(m_glibMainLoop);
|
|
|
|
|
m_events->addEvent(EventTypes::Quit);
|
2024-08-30 14:53:25 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Socket ownership is transferred to the EiScreen
|
2025-06-20 00:49:53 +00:00
|
|
|
m_events->addEvent(Event(EventTypes::EIConnected, m_screen->getEventTarget(), EiScreen::EiConnectInfo::alloc(fd)));
|
2024-08-30 14:53:25 +00:00
|
|
|
|
|
|
|
|
// FIXME: the lambda trick doesn't work here for unknown reasons, we need
|
|
|
|
|
// the static function
|
2025-06-20 00:49:53 +00:00
|
|
|
m_signals[DISABLED] = g_signal_connect(G_OBJECT(session), "disabled", G_CALLBACK(disabled), this);
|
|
|
|
|
m_signals[ACTIVATED] = g_signal_connect(G_OBJECT(m_session), "activated", G_CALLBACK(activated), this);
|
|
|
|
|
m_signals[DEACTIVATED] = g_signal_connect(G_OBJECT(m_session), "deactivated", G_CALLBACK(deactivated), this);
|
|
|
|
|
m_signals[ZONES_CHANGED] = g_signal_connect(G_OBJECT(m_session), "zones-changed", G_CALLBACK(zonesChanged), this);
|
2024-08-30 14:53:25 +00:00
|
|
|
XdpSession *parent_session = xdp_input_capture_session_get_session(session);
|
2025-06-20 00:49:53 +00:00
|
|
|
m_signals[SESSION_CLOSED] = g_signal_connect(G_OBJECT(parent_session), "closed", G_CALLBACK(sessionClosed), this);
|
2024-08-30 14:53:25 +00:00
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
handleZonesChanged(m_session, nullptr);
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-20 02:29:34 +00:00
|
|
|
void PortalInputCapture::handleSetPointerBarriers(const GObject *, GAsyncResult *res)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-08-30 14:53:25 +00:00
|
|
|
g_autoptr(GError) error = nullptr;
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
auto failed_list = xdp_input_capture_session_set_pointer_barriers_finish(m_session, res, &error);
|
2024-08-30 14:53:25 +00:00
|
|
|
if (failed_list) {
|
|
|
|
|
auto it = failed_list;
|
|
|
|
|
while (it) {
|
|
|
|
|
guint id;
|
|
|
|
|
g_object_get(it->data, "id", &id, nullptr);
|
2025-06-20 00:49:53 +00:00
|
|
|
for (auto elem = m_barriers.begin(); elem != m_barriers.end(); elem++) {
|
2024-08-30 14:53:25 +00:00
|
|
|
if (*elem == it->data) {
|
2025-05-20 02:14:18 +00:00
|
|
|
int x1;
|
|
|
|
|
int x2;
|
|
|
|
|
int y1;
|
|
|
|
|
int y2;
|
2024-08-30 14:53:25 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
g_object_get(G_OBJECT(*elem), "x1", &x1, "x2", &x2, "y1", &y1, "y2", &y2, nullptr);
|
2024-08-30 14:53:25 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
LOG_WARN("failed to apply barrier %d (%d/%d-%d/%d)", id, x1, y1, x2, y2);
|
2024-08-30 14:53:25 +00:00
|
|
|
g_object_unref(*elem);
|
2025-06-20 00:49:53 +00:00
|
|
|
m_barriers.erase(elem);
|
2024-08-30 14:53:25 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
it = it->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g_list_free_full(failed_list, g_object_unref);
|
|
|
|
|
|
|
|
|
|
enable();
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
gboolean PortalInputCapture::initSession()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-08-30 14:53:25 +00:00
|
|
|
LOG_DEBUG("setting up input capture session");
|
|
|
|
|
xdp_portal_create_input_capture_session(
|
2025-06-20 00:49:53 +00:00
|
|
|
m_portal,
|
2024-08-30 14:53:25 +00:00
|
|
|
nullptr, // parent
|
2024-10-17 18:04:35 +00:00
|
|
|
static_cast<XdpInputCapability>(XDP_INPUT_CAPABILITY_KEYBOARD | XDP_INPUT_CAPABILITY_POINTER),
|
2024-08-30 14:53:25 +00:00
|
|
|
nullptr, // cancellable
|
|
|
|
|
[](GObject *obj, GAsyncResult *res, gpointer data) {
|
2025-06-20 00:49:53 +00:00
|
|
|
static_cast<PortalInputCapture *>(data)->handleInitSession(obj, res);
|
2024-08-30 14:53:25 +00:00
|
|
|
},
|
2024-10-17 18:04:35 +00:00
|
|
|
this
|
|
|
|
|
);
|
2024-08-30 14:53:25 +00:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void PortalInputCapture::enable()
|
|
|
|
|
{
|
2025-06-20 00:49:53 +00:00
|
|
|
if (!m_enabled) {
|
2024-08-30 14:53:25 +00:00
|
|
|
LOG_DEBUG("enabling the portal input capture session");
|
2025-06-20 00:49:53 +00:00
|
|
|
xdp_input_capture_session_enable(m_session);
|
|
|
|
|
m_enabled = true;
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void PortalInputCapture::disable()
|
|
|
|
|
{
|
2025-06-20 00:49:53 +00:00
|
|
|
if (m_enabled) {
|
2024-08-30 14:53:25 +00:00
|
|
|
LOG_DEBUG("disabling the portal input capture session");
|
2025-06-20 00:49:53 +00:00
|
|
|
xdp_input_capture_session_disable(m_session);
|
|
|
|
|
m_enabled = false;
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void PortalInputCapture::release()
|
|
|
|
|
{
|
2025-06-20 00:49:53 +00:00
|
|
|
LOG_DEBUG("releasing input capture session, id=%d", m_activationId);
|
|
|
|
|
xdp_input_capture_session_release(m_session, m_activationId);
|
|
|
|
|
m_isActive = false;
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void PortalInputCapture::release(double x, double y)
|
|
|
|
|
{
|
2025-06-20 00:49:53 +00:00
|
|
|
LOG_DEBUG("releasing input capture session, id=%d x=%.1f y=%.1f", m_activationId, x, y);
|
|
|
|
|
xdp_input_capture_session_release_at(m_session, m_activationId, x, y);
|
|
|
|
|
m_isActive = false;
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-20 02:29:34 +00:00
|
|
|
void PortalInputCapture::handleDisabled(const XdpInputCaptureSession *, const GVariant *)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-08-30 14:53:25 +00:00
|
|
|
LOG_DEBUG("portal cb disabled");
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
if (!m_enabled)
|
2024-08-30 14:53:25 +00:00
|
|
|
return; // Nothing to do
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
m_enabled = false;
|
|
|
|
|
m_isActive = false;
|
2024-08-30 14:53:25 +00:00
|
|
|
|
|
|
|
|
// FIXME: need some better heuristics here of when we want to enable again
|
|
|
|
|
// But we don't know *why* we got disabled (and it's doubtfull we ever
|
|
|
|
|
// will), so we just assume that the zones will change or something and we
|
|
|
|
|
// can re-enable again
|
|
|
|
|
// ... very soon
|
|
|
|
|
g_timeout_add(
|
|
|
|
|
1000,
|
|
|
|
|
[](gpointer data) -> gboolean {
|
2025-05-23 18:32:42 +00:00
|
|
|
static_cast<PortalInputCapture *>(data)->enable();
|
2024-08-30 14:53:25 +00:00
|
|
|
return false;
|
|
|
|
|
},
|
2024-10-17 18:04:35 +00:00
|
|
|
this
|
|
|
|
|
);
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-20 02:29:34 +00:00
|
|
|
void PortalInputCapture::handleActivated(const XdpInputCaptureSession *, std::uint32_t activationId, GVariant *options)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-06-20 00:49:53 +00:00
|
|
|
LOG_DEBUG("portal cb activated, id=%d", activationId);
|
2024-08-30 14:53:25 +00:00
|
|
|
|
|
|
|
|
if (options) {
|
2025-05-20 02:14:18 +00:00
|
|
|
gdouble x;
|
|
|
|
|
gdouble y;
|
2024-08-30 14:53:25 +00:00
|
|
|
if (g_variant_lookup(options, "cursor_position", "(dd)", &x, &y)) {
|
2025-06-20 00:49:53 +00:00
|
|
|
m_screen->warpCursor((int)x, (int)y);
|
2024-08-30 14:53:25 +00:00
|
|
|
} else {
|
|
|
|
|
LOG_WARN("failed to get cursor position");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
LOG_WARN("activation has no options");
|
|
|
|
|
}
|
2025-06-20 00:49:53 +00:00
|
|
|
m_activationId = activationId;
|
|
|
|
|
m_isActive = true;
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-20 02:29:34 +00:00
|
|
|
void PortalInputCapture::handleDeactivated(const XdpInputCaptureSession *, std::uint32_t activationId, const GVariant *)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-06-20 00:49:53 +00:00
|
|
|
LOG_DEBUG("cb deactivated, id=%i", activationId);
|
|
|
|
|
m_isActive = false;
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-20 02:29:34 +00:00
|
|
|
void PortalInputCapture::handleZonesChanged(XdpInputCaptureSession *session, const GVariant *)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-06-20 00:49:53 +00:00
|
|
|
for (auto b : m_barriers)
|
2024-08-30 14:53:25 +00:00
|
|
|
g_object_unref(b);
|
2025-06-20 00:49:53 +00:00
|
|
|
m_barriers.clear();
|
2024-08-30 14:53:25 +00:00
|
|
|
|
|
|
|
|
auto zones = xdp_input_capture_session_get_zones(session);
|
|
|
|
|
while (zones != nullptr) {
|
2025-05-20 02:14:18 +00:00
|
|
|
guint w;
|
|
|
|
|
guint h;
|
|
|
|
|
gint x;
|
|
|
|
|
gint y;
|
2024-10-17 18:04:35 +00:00
|
|
|
g_object_get(zones->data, "width", &w, "height", &h, "x", &x, "y", &y, nullptr);
|
2024-08-30 14:53:25 +00:00
|
|
|
|
|
|
|
|
LOG_DEBUG("input capture zone, %dx%d@%d,%d", w, h, x, y);
|
|
|
|
|
|
2025-05-20 02:14:18 +00:00
|
|
|
int x1;
|
|
|
|
|
int x2;
|
|
|
|
|
int y1;
|
|
|
|
|
int y2;
|
2024-08-30 14:53:25 +00:00
|
|
|
|
|
|
|
|
// Hardcoded behaviour: our pointer barriers are always at the edges of
|
|
|
|
|
// all zones. Since the implementation is supposed to reject the ones in
|
|
|
|
|
// the wrong place, we can just install barriers everywhere and let EIS
|
|
|
|
|
// figure it out. Also a lot easier to implement for now though it doesn't
|
|
|
|
|
// cover differently-sized screens...
|
2025-06-20 00:49:53 +00:00
|
|
|
auto id = m_barriers.size() + 1;
|
2024-08-30 14:53:25 +00:00
|
|
|
x1 = x;
|
|
|
|
|
y1 = y;
|
|
|
|
|
x2 = x + w - 1;
|
|
|
|
|
y2 = y;
|
|
|
|
|
LOG_DEBUG("barrier (top) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2);
|
2025-06-20 00:49:53 +00:00
|
|
|
m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(
|
2024-10-17 18:04:35 +00:00
|
|
|
g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr)
|
|
|
|
|
));
|
2025-06-20 00:49:53 +00:00
|
|
|
id = m_barriers.size() + 1;
|
2024-08-30 14:53:25 +00:00
|
|
|
x1 = x + w;
|
|
|
|
|
y1 = y;
|
|
|
|
|
x2 = x + w;
|
|
|
|
|
y2 = y + h - 1;
|
|
|
|
|
LOG_DEBUG("barrier (right) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2);
|
2025-06-20 00:49:53 +00:00
|
|
|
m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(
|
2024-10-17 18:04:35 +00:00
|
|
|
g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr)
|
|
|
|
|
));
|
2025-06-20 00:49:53 +00:00
|
|
|
id = m_barriers.size() + 1;
|
2024-08-30 14:53:25 +00:00
|
|
|
x1 = x;
|
|
|
|
|
y1 = y;
|
|
|
|
|
x2 = x;
|
|
|
|
|
y2 = y + h - 1;
|
|
|
|
|
LOG_DEBUG("barrier (left) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2);
|
2025-06-20 00:49:53 +00:00
|
|
|
m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(
|
2024-10-17 18:04:35 +00:00
|
|
|
g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr)
|
|
|
|
|
));
|
2025-06-20 00:49:53 +00:00
|
|
|
id = m_barriers.size() + 1;
|
2024-08-30 14:53:25 +00:00
|
|
|
x1 = x;
|
|
|
|
|
y1 = y + h;
|
|
|
|
|
x2 = x + w - 1;
|
|
|
|
|
y2 = y + h;
|
|
|
|
|
LOG_DEBUG("barrier (bottom) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2);
|
2025-06-20 00:49:53 +00:00
|
|
|
m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(
|
2024-10-17 18:04:35 +00:00
|
|
|
g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr)
|
|
|
|
|
));
|
2024-08-30 14:53:25 +00:00
|
|
|
zones = zones->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GList *list = nullptr;
|
2025-06-20 00:49:53 +00:00
|
|
|
for (auto const &b : m_barriers) {
|
2024-08-30 14:53:25 +00:00
|
|
|
list = g_list_append(list, b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xdp_input_capture_session_set_pointer_barriers(
|
2025-06-20 00:49:53 +00:00
|
|
|
m_session, list,
|
2024-08-30 14:53:25 +00:00
|
|
|
nullptr, // cancellable
|
|
|
|
|
[](GObject *obj, GAsyncResult *res, gpointer data) {
|
2025-06-20 00:49:53 +00:00
|
|
|
static_cast<PortalInputCapture *>(data)->handleSetPointerBarriers(obj, res);
|
2024-08-30 14:53:25 +00:00
|
|
|
},
|
2024-10-17 18:04:35 +00:00
|
|
|
this
|
|
|
|
|
);
|
2024-08-30 14:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
void PortalInputCapture::glibThread(void *)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-06-20 00:49:53 +00:00
|
|
|
auto context = g_main_loop_get_context(m_glibMainLoop);
|
2024-08-30 14:53:25 +00:00
|
|
|
|
|
|
|
|
LOG_DEBUG("glib thread running");
|
|
|
|
|
|
2025-06-20 00:49:53 +00:00
|
|
|
while (g_main_loop_is_running(m_glibMainLoop)) {
|
2024-08-30 14:53:25 +00:00
|
|
|
Thread::testCancel();
|
|
|
|
|
g_main_context_iteration(context, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("shutting down glib thread");
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-17 19:00:25 +00:00
|
|
|
} // namespace deskflow
|