feat: handle input capture session persistence
Use the new libportal API to start a CreateSession2, then set the session persistence and read/write the tokens as required. This allows us to start a server without a permission dialog - provided the portal supports it and the user is ok with that.
This commit is contained in:
parent
7b614215a1
commit
1c789fd6a9
5 changed files with 122 additions and 12 deletions
|
|
@ -145,6 +145,7 @@ This section contains options used when in server mode it will begin with `[serv
|
||||||
| externalConfig | `true` or `false` | When true use the external config path |
|
| externalConfig | `true` or `false` | When true use the external config path |
|
||||||
| externalConfigFile | Filepath | Path the server config file if it does not exist the GUI will it generated based on the `internalConfig` section.|
|
| externalConfigFile | Filepath | Path the server config file if it does not exist the GUI will it generated based on the `internalConfig` section.|
|
||||||
| protocol | `barrier` or `synergy` | The protocol to use when saying hello to clients. Can be set to barrier or synergy. If not set barrier is used as the default |
|
| protocol | `barrier` or `synergy` | The protocol to use when saying hello to clients. Can be set to barrier or synergy. If not set barrier is used as the default |
|
||||||
|
| xdpRestoreToken | UUID | Restore token provided by XDG portals |
|
||||||
|
|
||||||
### InternalConfig
|
### InternalConfig
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ public:
|
||||||
inline static const auto ExternalConfig = QStringLiteral("server/externalConfig");
|
inline static const auto ExternalConfig = QStringLiteral("server/externalConfig");
|
||||||
inline static const auto ExternalConfigFile = QStringLiteral("server/externalConfigFile");
|
inline static const auto ExternalConfigFile = QStringLiteral("server/externalConfigFile");
|
||||||
inline static const auto Protocol = QStringLiteral("server/protocol");
|
inline static const auto Protocol = QStringLiteral("server/protocol");
|
||||||
|
inline static const auto XdpRestoreToken = QStringLiteral("server/xdpRestoreToken");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Enums types used in settings
|
// Enums types used in settings
|
||||||
|
|
@ -253,6 +254,7 @@ private:
|
||||||
, Settings::Server::ExternalConfig
|
, Settings::Server::ExternalConfig
|
||||||
, Settings::Server::ExternalConfigFile
|
, Settings::Server::ExternalConfigFile
|
||||||
, Settings::Server::Protocol
|
, Settings::Server::Protocol
|
||||||
|
, Settings::Server::XdpRestoreToken
|
||||||
};
|
};
|
||||||
|
|
||||||
// When checking the default values this list contains the ones that default to false.
|
// When checking the default values this list contains the ones that default to false.
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,15 @@ if(UNIX AND NOT APPLE)
|
||||||
|
|
||||||
pkg_check_modules(LIBPORTAL REQUIRED QUIET "libportal >= ${REQUIRED_LIBPORTAL_VERSION}")
|
pkg_check_modules(LIBPORTAL REQUIRED QUIET "libportal >= ${REQUIRED_LIBPORTAL_VERSION}")
|
||||||
message(STATUS "libportal version: ${LIBPORTAL_VERSION}")
|
message(STATUS "libportal version: ${LIBPORTAL_VERSION}")
|
||||||
|
|
||||||
|
# Check if we have the restore ability in the IC portal
|
||||||
|
include(CMakePushCheckState)
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
cmake_push_check_state(RESET)
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES};${LIBPORTAL_INCLUDE_DIRS};${GLIB2_INCLUDE_DIRS}")
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};${LIBPORTAL_LINK_LIBRARIES};${GLIB2_LINK_LIBRARIES}")
|
||||||
|
check_symbol_exists(xdp_input_capture_session_get_restore_token "libportal/inputcapture.h" HAVE_IC_RESTORE)
|
||||||
|
cmake_pop_check_state()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|
@ -178,6 +187,9 @@ if(UNIX)
|
||||||
target_compile_definitions(platform PRIVATE HAVE_XKB_KEYMAP_MOD_GET_MASK=1)
|
target_compile_definitions(platform PRIVATE HAVE_XKB_KEYMAP_MOD_GET_MASK=1)
|
||||||
endif()
|
endif()
|
||||||
target_compile_definitions(platform PUBLIC WINAPI_LIBEI WINAPI_LIBPORTAL)
|
target_compile_definitions(platform PUBLIC WINAPI_LIBEI WINAPI_LIBPORTAL)
|
||||||
|
if (HAVE_IC_RESTORE)
|
||||||
|
target_compile_definitions(platform PUBLIC HAVE_LIBPORTAL_INPUTCAPTURE_RESTORE)
|
||||||
|
endif()
|
||||||
target_include_directories(platform PUBLIC ${LIBEI_INCLUDE_DIRS} ${LIBPORTAL_INCLUDE_DIRS})
|
target_include_directories(platform PUBLIC ${LIBEI_INCLUDE_DIRS} ${LIBPORTAL_INCLUDE_DIRS})
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
platform
|
platform
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "base/TMethodJob.h"
|
#include "base/TMethodJob.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPORTAL_INPUTCAPTURE_RESTORE
|
||||||
|
#include "common/Settings.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sys/socket.h> // for EIS fd hack, remove
|
#include <sys/socket.h> // for EIS fd hack, remove
|
||||||
#include <sys/un.h> // for EIS fd hack, remove
|
#include <sys/un.h> // for EIS fd hack, remove
|
||||||
|
|
||||||
|
|
@ -20,6 +24,7 @@ namespace deskflow {
|
||||||
PortalInputCapture::PortalInputCapture(EiScreen *screen, IEventQueue *events)
|
PortalInputCapture::PortalInputCapture(EiScreen *screen, IEventQueue *events)
|
||||||
: m_screen{screen},
|
: m_screen{screen},
|
||||||
m_events{events},
|
m_events{events},
|
||||||
|
m_portalVersion(0),
|
||||||
m_portal{xdp_portal_new()}
|
m_portal{xdp_portal_new()}
|
||||||
{
|
{
|
||||||
m_glibMainLoop = g_main_loop_new(nullptr, true);
|
m_glibMainLoop = g_main_loop_new(nullptr, true);
|
||||||
|
|
@ -79,21 +84,10 @@ void PortalInputCapture::handleSessionClosed(XdpSession *session)
|
||||||
m_signals.at(Signal::SessionClosed) = 0;
|
m_signals.at(Signal::SessionClosed) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortalInputCapture::handleInitSession(GObject *object, GAsyncResult *res)
|
void PortalInputCapture::setupSession(XdpInputCaptureSession *session)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("portal input capture session initialized");
|
|
||||||
g_autoptr(GError) error = nullptr;
|
g_autoptr(GError) error = nullptr;
|
||||||
|
|
||||||
auto session = xdp_portal_create_input_capture_session_finish(XDP_PORTAL(object), res, &error);
|
|
||||||
if (!session) {
|
|
||||||
LOG_ERR("failed to initialize input capture session, quitting: %s", error->message);
|
|
||||||
g_main_loop_quit(m_glibMainLoop);
|
|
||||||
m_events->addEvent(Event(EventTypes::Quit));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_session = session;
|
|
||||||
|
|
||||||
auto fd = xdp_input_capture_session_connect_to_eis(session, &error);
|
auto fd = xdp_input_capture_session_connect_to_eis(session, &error);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
LOG_ERR("failed to connect to eis: %s", error->message);
|
LOG_ERR("failed to connect to eis: %s", error->message);
|
||||||
|
|
@ -115,6 +109,46 @@ void PortalInputCapture::handleInitSession(GObject *object, GAsyncResult *res)
|
||||||
handleZonesChanged(m_session, nullptr);
|
handleZonesChanged(m_session, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PortalInputCapture::handleInitSession(GObject *object, GAsyncResult *res)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) error = nullptr;
|
||||||
|
|
||||||
|
LOG_DEBUG("portal input capture session initialized");
|
||||||
|
|
||||||
|
auto session = xdp_portal_create_input_capture_session_finish(XDP_PORTAL(object), res, &error);
|
||||||
|
if (!session) {
|
||||||
|
LOG_ERR("failed to initialize input capture session, quitting: %s", error->message);
|
||||||
|
g_main_loop_quit(m_glibMainLoop);
|
||||||
|
m_events->addEvent(Event(EventTypes::Quit));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_session = session;
|
||||||
|
|
||||||
|
setupSession(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortalInputCapture::handleStart(GObject *object, GAsyncResult *res)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) error = nullptr;
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPORTAL_INPUTCAPTURE_RESTORE
|
||||||
|
LOG_DEBUG("portal input capture session initialized");
|
||||||
|
if (!xdp_input_capture_session_start_finish(m_session, res, &error)) {
|
||||||
|
LOG_ERR("failed to start input capture session, quitting: %s", error->message);
|
||||||
|
g_main_loop_quit(m_glibMainLoop);
|
||||||
|
m_events->addEvent(Event(EventTypes::Quit));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto restoreToken = xdp_input_capture_session_get_restore_token(m_session);
|
||||||
|
if (restoreToken) {
|
||||||
|
Settings::setValue(Settings::Server::XdpRestoreToken, QString(restoreToken));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
setupSession(m_session);
|
||||||
|
}
|
||||||
|
|
||||||
void PortalInputCapture::handleSetPointerBarriers(const GObject *, GAsyncResult *res)
|
void PortalInputCapture::handleSetPointerBarriers(const GObject *, GAsyncResult *res)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = nullptr;
|
g_autoptr(GError) error = nullptr;
|
||||||
|
|
@ -151,6 +185,22 @@ void PortalInputCapture::handleSetPointerBarriers(const GObject *, GAsyncResult
|
||||||
gboolean PortalInputCapture::initSession()
|
gboolean PortalInputCapture::initSession()
|
||||||
{
|
{
|
||||||
LOG_DEBUG("setting up input capture session");
|
LOG_DEBUG("setting up input capture session");
|
||||||
|
XdpInputCaptureSession *session;
|
||||||
|
#ifdef HAVE_LIBPORTAL_INPUTCAPTURE_RESTORE
|
||||||
|
g_autoptr(GError) error = nullptr;
|
||||||
|
|
||||||
|
m_portalVersion = xdp_portal_get_input_capture_version_sync(
|
||||||
|
m_portal,
|
||||||
|
nullptr, // Cancellable
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
LOG_DEBUG("input capture version %d", m_portalVersion);
|
||||||
|
|
||||||
|
switch (m_portalVersion) {
|
||||||
|
case 0:
|
||||||
|
LOG_WARN("portal bug: input capture version is %d", m_portalVersion);
|
||||||
|
// fallthrough
|
||||||
|
case 1:
|
||||||
xdp_portal_create_input_capture_session(
|
xdp_portal_create_input_capture_session(
|
||||||
m_portal,
|
m_portal,
|
||||||
nullptr, // parent
|
nullptr, // parent
|
||||||
|
|
@ -161,6 +211,48 @@ gboolean PortalInputCapture::initSession()
|
||||||
},
|
},
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
session = xdp_portal_create_input_capture_session2_sync(
|
||||||
|
m_portal,
|
||||||
|
nullptr, // Cancellable
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
if (!session) {
|
||||||
|
LOG_ERR("failed to initialize input capture session, quitting: %s", error->message);
|
||||||
|
g_main_loop_quit(m_glibMainLoop);
|
||||||
|
m_events->addEvent(Event(EventTypes::Quit));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
m_session = session;
|
||||||
|
xdp_input_capture_session_set_session_persistence(session, XDP_INPUT_CAPTURE_SESSION_PERSISTENCE_PERSISTENT);
|
||||||
|
if (auto sessionToken = Settings::value(Settings::Server::XdpRestoreToken).toByteArray(); !sessionToken.isEmpty()) {
|
||||||
|
xdp_input_capture_session_set_restore_token(session, strdup(sessionToken.data()));
|
||||||
|
}
|
||||||
|
xdp_input_capture_session_start(
|
||||||
|
m_session,
|
||||||
|
nullptr, // parent
|
||||||
|
static_cast<XdpInputCapability>(XDP_INPUT_CAPABILITY_KEYBOARD | XDP_INPUT_CAPABILITY_POINTER),
|
||||||
|
nullptr, // cancellable
|
||||||
|
[](GObject *obj, GAsyncResult *res, gpointer data) {
|
||||||
|
static_cast<PortalInputCapture *>(data)->handleStart(obj, res);
|
||||||
|
},
|
||||||
|
this
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
xdp_portal_create_input_capture_session(
|
||||||
|
m_portal,
|
||||||
|
nullptr, // parent
|
||||||
|
static_cast<XdpInputCapability>(XDP_INPUT_CAPABILITY_KEYBOARD | XDP_INPUT_CAPABILITY_POINTER),
|
||||||
|
nullptr, // cancellable
|
||||||
|
[](GObject *obj, GAsyncResult *res, gpointer data) {
|
||||||
|
static_cast<PortalInputCapture *>(data)->handleInitSession(obj, res);
|
||||||
|
},
|
||||||
|
this
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ private:
|
||||||
void glibThread(const void *);
|
void glibThread(const void *);
|
||||||
gboolean timeoutHandler() const;
|
gboolean timeoutHandler() const;
|
||||||
gboolean initSession();
|
gboolean initSession();
|
||||||
|
void setupSession(XdpInputCaptureSession *session);
|
||||||
|
void handleStart(GObject *object, GAsyncResult *res);
|
||||||
void handleInitSession(GObject *object, GAsyncResult *res);
|
void handleInitSession(GObject *object, GAsyncResult *res);
|
||||||
void handleSetPointerBarriers(const GObject *object, GAsyncResult *res);
|
void handleSetPointerBarriers(const GObject *object, GAsyncResult *res);
|
||||||
void handleSessionClosed(XdpSession *session);
|
void handleSessionClosed(XdpSession *session);
|
||||||
|
|
@ -83,6 +85,7 @@ private:
|
||||||
|
|
||||||
EiScreen *m_screen = nullptr;
|
EiScreen *m_screen = nullptr;
|
||||||
IEventQueue *m_events = nullptr;
|
IEventQueue *m_events = nullptr;
|
||||||
|
int m_portalVersion = 0;
|
||||||
|
|
||||||
Thread *m_glibThread;
|
Thread *m_glibThread;
|
||||||
GMainLoop *m_glibMainLoop = nullptr;
|
GMainLoop *m_glibMainLoop = nullptr;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue