177 lines
5.2 KiB
C++
177 lines
5.2 KiB
C++
/*
|
|
* Deskflow -- mouse and keyboard sharing utility
|
|
* SPDX-FileCopyrightText: (C) 2024 - 2026 Deskflow Developers
|
|
* SPDX-FileCopyrightText: (C) 2024, 2026 Synergy App Ltd
|
|
* SPDX-FileCopyrightText: (C) 2022, 2026 Red Hat, Inc.
|
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "mt/Thread.h"
|
|
#include "platform/EiScreen.h"
|
|
|
|
#include <QByteArray>
|
|
|
|
#include <glib.h>
|
|
#include <libportal/inputcapture.h>
|
|
#include <libportal/portal.h>
|
|
|
|
#include <cstdint>
|
|
#include <map>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace deskflow {
|
|
|
|
class EiClipboard;
|
|
|
|
class PortalInputCapture
|
|
{
|
|
public:
|
|
PortalInputCapture(EiScreen *screen, IEventQueue *events);
|
|
~PortalInputCapture();
|
|
|
|
// Get the clipboard for the specified ID
|
|
EiClipboard *getClipboard(ClipboardID id) const;
|
|
void enable();
|
|
void disable();
|
|
void release();
|
|
void release(double x, double y);
|
|
bool isActive() const
|
|
{
|
|
return m_isActive;
|
|
}
|
|
|
|
private:
|
|
void glibThread(const void *);
|
|
gboolean timeoutHandler() const;
|
|
gboolean initSession();
|
|
void setupSession(XdpInputCaptureSession *session);
|
|
void handleStart(GObject *object, GAsyncResult *res);
|
|
void handleInitSession(GObject *object, GAsyncResult *res);
|
|
void handleSetPointerBarriers(const GObject *object, GAsyncResult *res);
|
|
void handleSessionClosed(XdpSession *session);
|
|
void handleDisabled(const XdpInputCaptureSession *session, const GVariant *option);
|
|
void handleActivated(const XdpInputCaptureSession *session, const std::uint32_t activationId, GVariant *options);
|
|
void
|
|
handleDeactivated(const XdpInputCaptureSession *session, const std::uint32_t activationId, const GVariant *options);
|
|
void handleZonesChanged(XdpInputCaptureSession *session, const GVariant *options);
|
|
|
|
void handleSelectionTransfer(XdpSession *session, const char *mimeType, uint32_t serial) const;
|
|
void readClipboardSelection(XdpSession *session) const;
|
|
void claimClipboardOwnership(XdpSession *session) const;
|
|
|
|
/// g_signal_connect callback wrapper
|
|
static void sessionClosed(XdpSession *session, const gpointer data)
|
|
{
|
|
static_cast<PortalInputCapture *>(data)->handleSessionClosed(session);
|
|
}
|
|
static void disabled(const XdpInputCaptureSession *session, const GVariant *options, const gpointer data)
|
|
{
|
|
static_cast<PortalInputCapture *>(data)->handleDisabled(session, options);
|
|
}
|
|
static void activated(
|
|
const XdpInputCaptureSession *session, const std::uint32_t activationId, GVariant *options, const gpointer data
|
|
)
|
|
{
|
|
static_cast<PortalInputCapture *>(data)->handleActivated(session, activationId, options);
|
|
}
|
|
static void deactivated(
|
|
const XdpInputCaptureSession *session, const std::uint32_t activationId, const GVariant *options,
|
|
const gpointer data
|
|
)
|
|
{
|
|
static_cast<PortalInputCapture *>(data)->handleDeactivated(session, activationId, options);
|
|
}
|
|
static void zonesChanged(XdpInputCaptureSession *session, const GVariant *options, const gpointer data)
|
|
{
|
|
static_cast<PortalInputCapture *>(data)->handleZonesChanged(session, options);
|
|
}
|
|
static void selectionTransfer(XdpSession *session, const char *mimeType, uint32_t serial, const gpointer data)
|
|
{
|
|
static_cast<PortalInputCapture *>(data)->handleSelectionTransfer(session, mimeType, serial);
|
|
}
|
|
|
|
enum class Signal : uint8_t
|
|
{
|
|
SessionClosed,
|
|
Disabled,
|
|
Activated,
|
|
Deactivated,
|
|
ZonesChanged,
|
|
|
|
// Clipboard signals
|
|
SelectionTransfer,
|
|
};
|
|
|
|
enum class BarrierSide : uint8_t
|
|
{
|
|
Left,
|
|
Right,
|
|
Top,
|
|
Bottom
|
|
};
|
|
|
|
struct BarrierInfo
|
|
{
|
|
guint id = 0;
|
|
BarrierSide side = BarrierSide::Left;
|
|
gint x = 0;
|
|
gint y = 0;
|
|
guint width = 0;
|
|
guint height = 0;
|
|
gint x1 = 0;
|
|
gint y1 = 0;
|
|
gint x2 = 0;
|
|
gint y2 = 0;
|
|
};
|
|
|
|
struct Bounds
|
|
{
|
|
gint left = 0;
|
|
gint top = 0;
|
|
gint right = 0;
|
|
gint bottom = 0;
|
|
};
|
|
|
|
static const char *barrierSideName(BarrierSide side);
|
|
static int
|
|
scaleCoordinateBetweenRanges(double value, int sourceMin, int sourceMax, int destinationMin, int destinationMax);
|
|
bool getPortalBounds(Bounds &bounds) const;
|
|
bool getClosestReleaseBarrier(
|
|
double x, double y, int screenLeft, int screenTop, int screenRight, int screenBottom, const Bounds &portalBounds,
|
|
BarrierInfo &barrier
|
|
) const;
|
|
std::pair<int, int> mapPortalActivationToScreenPosition(guint barrierId, double rawX, double rawY) const;
|
|
std::pair<double, double> mapPortalReleasePosition(double x, double y) const;
|
|
void addBarrier(guint id, BarrierSide side, gint zoneX, gint zoneY, guint zoneWidth, guint zoneHeight);
|
|
|
|
EiScreen *m_screen = nullptr;
|
|
IEventQueue *m_events = nullptr;
|
|
int m_portalVersion = 0;
|
|
|
|
Thread *m_glibThread;
|
|
GMainLoop *m_glibMainLoop = nullptr;
|
|
|
|
XdpPortal *m_portal = nullptr;
|
|
XdpInputCaptureSession *m_session = nullptr;
|
|
|
|
std::map<Signal, gulong> m_signals = {
|
|
{Signal::SessionClosed, 0}, {Signal::Disabled, 0}, {Signal::Activated, 0},
|
|
{Signal::Deactivated, 0}, {Signal::ZonesChanged, 0},
|
|
|
|
{Signal::SelectionTransfer, 0},
|
|
};
|
|
|
|
bool m_enabled = false;
|
|
bool m_isActive = false;
|
|
std::uint32_t m_activationId = 0;
|
|
|
|
std::vector<XdpInputCapturePointerBarrier *> m_barriers;
|
|
std::vector<BarrierInfo> m_barrierInfo;
|
|
|
|
EiClipboard *m_clipboard = nullptr;
|
|
};
|
|
|
|
} // namespace deskflow
|