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 |
|
||||
| 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 |
|
||||
| xdpRestoreToken | UUID | Restore token provided by XDG portals |
|
||||
|
||||
### InternalConfig
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ public:
|
|||
inline static const auto ExternalConfig = QStringLiteral("server/externalConfig");
|
||||
inline static const auto ExternalConfigFile = QStringLiteral("server/externalConfigFile");
|
||||
inline static const auto Protocol = QStringLiteral("server/protocol");
|
||||
inline static const auto XdpRestoreToken = QStringLiteral("server/xdpRestoreToken");
|
||||
};
|
||||
|
||||
// Enums types used in settings
|
||||
|
|
@ -253,6 +254,7 @@ private:
|
|||
, Settings::Server::ExternalConfig
|
||||
, Settings::Server::ExternalConfigFile
|
||||
, Settings::Server::Protocol
|
||||
, Settings::Server::XdpRestoreToken
|
||||
};
|
||||
|
||||
// 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}")
|
||||
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()
|
||||
|
||||
if(WIN32)
|
||||
|
|
@ -178,6 +187,9 @@ if(UNIX)
|
|||
target_compile_definitions(platform PRIVATE HAVE_XKB_KEYMAP_MOD_GET_MASK=1)
|
||||
endif()
|
||||
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_link_libraries(
|
||||
platform
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@
|
|||
#include "base/Log.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/un.h> // for EIS fd hack, remove
|
||||
|
||||
|
|
@ -20,6 +24,7 @@ namespace deskflow {
|
|||
PortalInputCapture::PortalInputCapture(EiScreen *screen, IEventQueue *events)
|
||||
: m_screen{screen},
|
||||
m_events{events},
|
||||
m_portalVersion(0),
|
||||
m_portal{xdp_portal_new()}
|
||||
{
|
||||
m_glibMainLoop = g_main_loop_new(nullptr, true);
|
||||
|
|
@ -79,21 +84,10 @@ void PortalInputCapture::handleSessionClosed(XdpSession *session)
|
|||
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;
|
||||
|
||||
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);
|
||||
if (fd < 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
g_autoptr(GError) error = nullptr;
|
||||
|
|
@ -151,6 +185,63 @@ void PortalInputCapture::handleSetPointerBarriers(const GObject *, GAsyncResult
|
|||
gboolean PortalInputCapture::initSession()
|
||||
{
|
||||
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(
|
||||
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
|
||||
);
|
||||
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
|
||||
|
|
@ -161,6 +252,7 @@ gboolean PortalInputCapture::initSession()
|
|||
},
|
||||
this
|
||||
);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ 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);
|
||||
|
|
@ -83,6 +85,7 @@ private:
|
|||
|
||||
EiScreen *m_screen = nullptr;
|
||||
IEventQueue *m_events = nullptr;
|
||||
int m_portalVersion = 0;
|
||||
|
||||
Thread *m_glibThread;
|
||||
GMainLoop *m_glibMainLoop = nullptr;
|
||||
|
|
|
|||
Loading…
Reference in a new issue