diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6486c7e..bb2aaec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -84,11 +84,12 @@ else()
set(HYPRLAND_PROTOCOLS "${CMAKE_SOURCE_DIR}/subprojects/hyprland-protocols")
endif()
+pkg_search_module(UUID REQUIRED uuid)
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
add_executable(xdg-desktop-portal-hyprland ${SRCFILES})
target_link_libraries(
xdg-desktop-portal-hyprland PRIVATE rt PkgConfig::SDBUS Threads::Threads
- PkgConfig::deps)
+ PkgConfig::deps ${UUID_LIBRARIES})
# protocols
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
@@ -127,6 +128,8 @@ protocolwayland()
protocolnew("${CMAKE_SOURCE_DIR}/protocols"
"wlr-foreign-toplevel-management-unstable-v1" true)
protocolnew("${CMAKE_SOURCE_DIR}/protocols" "wlr-screencopy-unstable-v1" true)
+protocolnew("${CMAKE_SOURCE_DIR}/protocols" "wlr-virtual-pointer-unstable-v1" true)
+protocolnew("${CMAKE_SOURCE_DIR}/protocols" "virtual-keyboard-unstable-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-global-shortcuts-v1"
true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-export-v1"
diff --git a/hyprland.portal b/hyprland.portal
index cbaafa8..2e7ad8d 100644
--- a/hyprland.portal
+++ b/hyprland.portal
@@ -1,4 +1,4 @@
[portal]
DBusName=org.freedesktop.impl.portal.desktop.hyprland
-Interfaces=org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.ScreenCast;org.freedesktop.impl.portal.GlobalShortcuts;org.freedesktop.impl.portal.InputCapture;
+Interfaces=org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.ScreenCast;org.freedesktop.impl.portal.GlobalShortcuts;org.freedesktop.impl.portal.InputCapture;org.freedesktop.impl.portal.RemoteDesktop;
UseIn=wlroots;Hyprland;sway;Wayfire;river;
diff --git a/protocols/virtual-keyboard-unstable-v1.xml b/protocols/virtual-keyboard-unstable-v1.xml
new file mode 100644
index 0000000..5095c91
--- /dev/null
+++ b/protocols/virtual-keyboard-unstable-v1.xml
@@ -0,0 +1,113 @@
+
+
+
+ Copyright © 2008-2011 Kristian Høgsberg
+ Copyright © 2010-2013 Intel Corporation
+ Copyright © 2012-2013 Collabora, Ltd.
+ Copyright © 2018 Purism SPC
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+
+
+
+ The virtual keyboard provides an application with requests which emulate
+ the behaviour of a physical keyboard.
+
+ This interface can be used by clients on its own to provide raw input
+ events, or it can accompany the input method protocol.
+
+
+
+
+ Provide a file descriptor to the compositor which can be
+ memory-mapped to provide a keyboard mapping description.
+
+ Format carries a value from the keymap_format enumeration.
+
+
+
+
+
+
+
+
+
+
+
+
+ A key was pressed or released.
+ The time argument is a timestamp with millisecond granularity, with an
+ undefined base. All requests regarding a single object must share the
+ same clock.
+
+ Keymap must be set before issuing this request.
+
+ State carries a value from the key_state enumeration.
+
+
+
+
+
+
+
+
+ Notifies the compositor that the modifier and/or group state has
+ changed, and it should update state.
+
+ The client should use wl_keyboard.modifiers event to synchronize its
+ internal state with seat state.
+
+ Keymap must be set before issuing this request.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A virtual keyboard manager allows an application to provide keyboard
+ input events as if they came from a physical keyboard.
+
+
+
+
+
+
+
+
+ Creates a new virtual keyboard associated to a seat.
+
+ If the compositor enables a keyboard to perform arbitrary actions, it
+ should present an error when an untrusted client requests a new
+ keyboard.
+
+
+
+
+
+
diff --git a/protocols/wlr-virtual-pointer-unstable-v1.xml b/protocols/wlr-virtual-pointer-unstable-v1.xml
new file mode 100644
index 0000000..ea243e7
--- /dev/null
+++ b/protocols/wlr-virtual-pointer-unstable-v1.xml
@@ -0,0 +1,152 @@
+
+
+
+ Copyright © 2019 Josef Gajdusek
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+
+
+
+ This protocol allows clients to emulate a physical pointer device. The
+ requests are mostly mirror opposites of those specified in wl_pointer.
+
+
+
+
+
+
+
+
+
+ The pointer has moved by a relative amount to the previous request.
+
+ Values are in the global compositor space.
+
+
+
+
+
+
+
+
+ The pointer has moved in an absolute coordinate frame.
+
+ Value of x can range from 0 to x_extent, value of y can range from 0
+ to y_extent.
+
+
+
+
+
+
+
+
+
+
+ A button was pressed or released.
+
+
+
+
+
+
+
+
+ Scroll and other axis requests.
+
+
+
+
+
+
+
+
+ Indicates the set of events that logically belong together.
+
+
+
+
+
+ Source information for scroll and other axis.
+
+
+
+
+
+
+ Stop notification for scroll and other axes.
+
+
+
+
+
+
+
+ Discrete step information for scroll and other axes.
+
+ This event allows the client to extend data normally sent using the axis
+ event with discrete value.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This object allows clients to create individual virtual pointer objects.
+
+
+
+
+ Creates a new virtual pointer. The optional seat is a suggestion to the
+ compositor.
+
+
+
+
+
+
+
+
+
+
+
+
+ Creates a new virtual pointer. The seat and the output arguments are
+ optional. If the seat argument is set, the compositor should assign the
+ input device to the requested seat. If the output argument is set, the
+ compositor should map the input device to the requested output.
+
+
+
+
+
+
+
diff --git a/src/core/PortalManager.cpp b/src/core/PortalManager.cpp
index 8e0d266..2aff24f 100644
--- a/src/core/PortalManager.cpp
+++ b/src/core/PortalManager.cpp
@@ -31,7 +31,7 @@ SOutput::SOutput(SP output_) : output(output_) {
y = y_;
});
output->setScale([this](CCWlOutput* r, uint32_t factor_) { scale = factor_; });
- output->setDone([](CCWlOutput* r) { g_pPortalManager->m_sPortals.inputCapture->zonesChanged(); });
+ output->setDone([](CCWlOutput* r) {});
}
CPortalManager::CPortalManager() {
@@ -60,6 +60,7 @@ void CPortalManager::onGlobal(uint32_t name, const char* interface, uint32_t ver
Debug::log(LOG, " | Got interface: {} (ver {})", INTERFACE, version);
+
if (INTERFACE == zwlr_screencopy_manager_v1_interface.name && m_sPipewire.loop) {
m_sPortals.screencopy = std::make_unique(makeShared(
(wl_proxy*)wl_registry_bind((wl_registry*)m_sWaylandConnection.registry->resource(), name, &zwlr_screencopy_manager_v1_interface, version)));
@@ -69,9 +70,23 @@ void CPortalManager::onGlobal(uint32_t name, const char* interface, uint32_t ver
m_sPortals.globalShortcuts = std::make_unique(makeShared(
(wl_proxy*)wl_registry_bind((wl_registry*)m_sWaylandConnection.registry->resource(), name, &hyprland_global_shortcuts_manager_v1_interface, version)));
}
+
+ if (m_sPortals.remoteDesktop == nullptr)
+ m_sPortals.remoteDesktop = std::make_unique();
+
if (INTERFACE == hyprland_input_capture_manager_v1_interface.name)
m_sPortals.inputCapture = std::make_unique(makeShared(
(wl_proxy*)wl_registry_bind((wl_registry*)m_sWaylandConnection.registry->resource(), name, &hyprland_input_capture_manager_v1_interface, version)));
+
+ if (INTERFACE == zwlr_virtual_pointer_manager_v1_interface.name)
+ m_sPortals.remoteDesktop->registerPointer(makeShared(
+ (wl_proxy*)wl_registry_bind((wl_registry*)m_sWaylandConnection.registry->resource(), name, &zwlr_virtual_pointer_manager_v1_interface, version)));
+
+ if (INTERFACE == zwp_virtual_keyboard_manager_v1_interface.name)
+ m_sPortals.remoteDesktop->registerKeyboard(makeShared(
+ (wl_proxy*)wl_registry_bind((wl_registry*)m_sWaylandConnection.registry->resource(), name, &zwp_virtual_keyboard_manager_v1_interface, version)));
+
+
else if (INTERFACE == hyprland_toplevel_export_manager_v1_interface.name) {
m_sWaylandConnection.hyprlandToplevelMgr = makeShared(
(wl_proxy*)wl_registry_bind((wl_registry*)m_sWaylandConnection.registry->resource(), name, &hyprland_toplevel_export_manager_v1_interface, version));
@@ -85,6 +100,20 @@ void CPortalManager::onGlobal(uint32_t name, const char* interface, uint32_t ver
POUTPUT->id = name;
}
+ else if (INTERFACE == wl_seat_interface.name) {
+ m_sWaylandConnection.seat = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_sWaylandConnection.registry->resource(), name, &wl_seat_interface, version));
+ }
+
+ /*
+ else if (INTERFACE == wl_keyboard_interface.name) {
+ const auto PKEYBOARD = m_vKeyboards
+ .emplace_back(std::make_unique(makeShared(
+ (wl_proxy*)wl_registry_bind((wl_registry*)m_sWaylandConnection.registry->resource(), name, &wl_keyboard_interface, version))))
+ .get();
+ PKEYBOARD->id = name;
+ }
+ */
+
else if (INTERFACE == zwp_linux_dmabuf_v1_interface.name) {
if (version < 4) {
Debug::log(ERR, "cannot use linux_dmabuf with ver < 4");
@@ -419,8 +448,9 @@ void CPortalManager::startEventLoop() {
m_sPortals.globalShortcuts.reset();
m_sPortals.screencopy.reset();
m_sPortals.screenshot.reset();
- m_sHelpers.toplevel.reset();
m_sPortals.inputCapture.reset();
+ m_sPortals.remoteDesktop.reset();
+ m_sHelpers.toplevel.reset();
m_pConnection.reset();
pw_loop_destroy(m_sPipewire.loop);
diff --git a/src/core/PortalManager.hpp b/src/core/PortalManager.hpp
index c10e121..c5dd87f 100644
--- a/src/core/PortalManager.hpp
+++ b/src/core/PortalManager.hpp
@@ -9,6 +9,7 @@
#include "../portals/Screenshot.hpp"
#include "../portals/GlobalShortcuts.hpp"
#include "../portals/InputCapture.hpp"
+#include "../portals/RemoteDesktop.hpp"
#include "../helpers/Timer.hpp"
#include "../shared/ToplevelManager.hpp"
#include
@@ -20,6 +21,9 @@
#include "linux-dmabuf-v1.hpp"
#include "wlr-foreign-toplevel-management-unstable-v1.hpp"
#include "wlr-screencopy-unstable-v1.hpp"
+#include "hyprland-input-capture-v1.hpp"
+#include "wlr-virtual-pointer-unstable-v1.hpp"
+#include "virtual-keyboard-unstable-v1.hpp"
#include "../includes.hpp"
#include "../dbusDefines.hpp"
@@ -60,6 +64,12 @@ class CPortalManager {
SOutput* getOutputFromName(const std::string& name);
std::vector> const& getAllOutputs();
+ struct {
+ enum wl_keyboard_keymap_format format;
+ int32_t fd;
+ uint32_t size;
+ } m_sKeymap;
+
struct {
pw_loop* loop = nullptr;
} m_sPipewire;
@@ -69,6 +79,7 @@ class CPortalManager {
std::unique_ptr screenshot;
std::unique_ptr globalShortcuts;
std::unique_ptr inputCapture;
+ std::unique_ptr remoteDesktop;
} m_sPortals;
struct {
@@ -77,6 +88,7 @@ class CPortalManager {
struct {
wl_display* display = nullptr;
+ SP seat;
SP registry;
SP hyprlandToplevelMgr;
SP linuxDmabuf;
@@ -130,8 +142,8 @@ class CPortalManager {
std::unique_ptr thread;
} m_sTimersThread;
- std::unique_ptr m_pConnection;
- std::vector> m_vOutputs;
+ std::unique_ptr m_pConnection;
+ std::vector> m_vOutputs;
std::mutex m_mEventLock;
};
diff --git a/src/portals/InputCapture.cpp b/src/portals/InputCapture.cpp
index 4372a36..1aa35ec 100644
--- a/src/portals/InputCapture.cpp
+++ b/src/portals/InputCapture.cpp
@@ -25,7 +25,11 @@ CInputCapturePortal::CInputCapturePortal(SP mgr
});
mgr->setKeymap([this](CCHyprlandInputCaptureManagerV1* r, hyprlandInputCaptureManagerV1KeymapFormat format, int32_t fd, uint32_t size) {
+ Debug::log(LOG, "[input-capture] got keymap");
onKeymap(format == HYPRLAND_INPUT_CAPTURE_MANAGER_V1_KEYMAP_FORMAT_XKB_V1 ? fd : 0, size);
+ g_pPortalManager->m_sKeymap.format = wl_keyboard_keymap_format(format);
+ g_pPortalManager->m_sKeymap.fd = fd;
+ g_pPortalManager->m_sKeymap.size = size;
});
mgr->setModifiers([this](CCHyprlandInputCaptureManagerV1* r, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
@@ -128,7 +132,8 @@ dbUasv CInputCapturePortal::onCreateSession(sdbus::ObjectPath requestHandle, sdb
session->request = createDBusRequest(requestHandle);
session->request->onDestroy = [session]() { session->request.release(); };
- session->eis = std::make_unique("eis-" + sessionId, keymap);
+ session->eis = std::make_unique("eis-" + sessionId);
+ session->eis->setKeymap(keymap);
sessions.emplace(sessionHandle, session);
diff --git a/src/portals/RemoteDesktop.cpp b/src/portals/RemoteDesktop.cpp
new file mode 100644
index 0000000..551550f
--- /dev/null
+++ b/src/portals/RemoteDesktop.cpp
@@ -0,0 +1,207 @@
+#include "RemoteDesktop.hpp"
+#include "../core/PortalManager.hpp"
+#include "../helpers/Log.hpp"
+#include "../helpers/MiscFunctions.hpp"
+
+void CRemoteDesktopPortal::registerPointer(SP mgr) {
+ m_sState.pointerMgr = mgr;
+}
+
+void CRemoteDesktopPortal::registerKeyboard(SP mgr) {
+ m_sState.keyboardMgr = mgr;
+}
+
+CRemoteDesktopPortal::CRemoteDesktopPortal() {
+ Debug::log(LOG, "[remotedesktop] initializing remote desktop portal");
+ m_pObject = sdbus::createObject(*g_pPortalManager->getConnection(), OBJECT_PATH);
+ m_pObject
+ ->addVTable(
+ sdbus::registerMethod("CreateSession")
+ .implementedAs([this](sdbus::ObjectPath o1, sdbus::ObjectPath o2, std::string s, std::unordered_map m) {
+ return onCreateSession(o1, o2, s, m);
+ }),
+ sdbus::registerMethod("SelectDevices")
+ .implementedAs([this](sdbus::ObjectPath o1, sdbus::ObjectPath o2, std::string s, std::unordered_map m) {
+ return onSelectDevices(o1, o2, s, m);
+ }),
+ sdbus::registerMethod("Start")
+ .implementedAs([this](sdbus::ObjectPath o1, sdbus::ObjectPath o2, std::string s1, std::string s2, std::unordered_map m) {
+ return onStart(o1, o2, s1, s2, m);
+ }),
+ sdbus::registerMethod("NotifyPointerMotion")
+ .implementedAs([this](sdbus::ObjectPath o, double d1, double d2, std::unordered_map m) {
+ return onNotifyPointerMotion(o, d1, d2, m);
+ }),
+ sdbus::registerMethod("NotifyPointerMotionAbsolute")
+ .implementedAs([this](sdbus::ObjectPath o, unsigned int u, double d1, double d2, std::unordered_map m) {
+ return onNotifyPointerMotionAbsolute(o, u, d1, d2, m);
+ }),
+ sdbus::registerMethod("NotifyPointerButton")
+ .implementedAs([this](sdbus::ObjectPath o, int i, unsigned int u, std::unordered_map m) {
+ return onNotifyPointerButton(o, i, u, m);
+ }),
+ sdbus::registerMethod("NotifyPointerAxis")
+ .implementedAs([this](sdbus::ObjectPath o, double d1, double d2, std::unordered_map m) {
+ return onNotifyPointerAxis(o, d1, d2, m);
+ }),
+ sdbus::registerMethod("NotifyPointerAxisDiscrete")
+ .implementedAs([this](sdbus::ObjectPath o, unsigned int u, int i, std::unordered_map m) {
+ return onNotifyPointerAxisDiscrete(o, u, i, m);
+ }),
+ sdbus::registerMethod("NotifyKeyboardKeycode")
+ .implementedAs([this](sdbus::ObjectPath o, int i, unsigned int u, std::unordered_map m) {
+ return onNotifyKeyboardKeycode(o, i, u, m);
+ }),
+ sdbus::registerMethod("NotifyKeyboardKeysym")
+ .implementedAs([this](sdbus::ObjectPath o, int i, unsigned int u, std::unordered_map m) {
+ return onNotifyKeyboardKeysym(o, i, u, m);
+ }),
+ sdbus::registerMethod("NotifyTouchDown")
+ .implementedAs([this](sdbus::ObjectPath o, unsigned int u1, unsigned int u2, double d1, double d2, std::unordered_map m) {
+ return onNotifyTouchDown(o, u1, u2, d1, d2, m);
+ }),
+ sdbus::registerMethod("NotifyTouchMotion")
+ .implementedAs([this](sdbus::ObjectPath o, unsigned int u1, unsigned int u2, double d1, double d2, std::unordered_map m) {
+ return onNotifyTouchMotion(o, u1, u2, d1, d2, m);
+ }),
+ sdbus::registerMethod("NotifyTouchUp")
+ .implementedAs([this](sdbus::ObjectPath o, unsigned int u, std::unordered_map m) {
+ return onNotifyTouchUp(o, u, m);
+ }),
+ sdbus::registerMethod("ConnectToEIS").implementedAs([this](sdbus::ObjectPath o, std::string s, std::unordered_map m) {
+ return onConnectToEIS(o, s, m);
+ }),
+ sdbus::registerProperty("AvailableDeviceTypes").withGetter([] { return (uint32_t)(1 | 2); }),
+ sdbus::registerProperty("version").withGetter([] { return (uint32_t)(1); }))
+ .forInterface(INTERFACE_NAME);
+
+}
+
+dbUasv CRemoteDesktopPortal::onCreateSession(sdbus::ObjectPath requestHandle, sdbus::ObjectPath sessionHandle, std::string appID,
+ std::unordered_map opts) {
+ Debug::log(LOG, "[remotedesktop] New session:");
+ Debug::log(LOG, "[remotedesktop] | {}", requestHandle.c_str());
+ Debug::log(LOG, "[remotedesktop] | {}", sessionHandle.c_str());
+ Debug::log(LOG, "[remotedesktop] | appid: {}", appID);
+
+ std::shared_ptr PSESSION = std::make_shared(appID, requestHandle, sessionHandle);
+
+ // create objects
+ PSESSION->session = createDBusSession(sessionHandle);
+ PSESSION->sessionHandle = sessionHandle;
+ PSESSION->session->onDestroy = [PSESSION, this]() {
+ PSESSION->eis->stopServer();
+ PSESSION->eis.reset();
+ Debug::log(LOG, "[remotedesktop] Session {} destroyed", PSESSION->sessionHandle.c_str());
+ PSESSION->session.release();
+ m_mSessions.erase(PSESSION->sessionHandle);
+ };
+
+ PSESSION->request = createDBusRequest(requestHandle);
+ PSESSION->requestHandle = requestHandle;
+ PSESSION->request->onDestroy = [PSESSION]() { PSESSION->request.release(); };
+
+ PSESSION->pointer = makeShared(m_sState.pointerMgr->sendCreateVirtualPointer(g_pPortalManager->m_sWaylandConnection.seat->resource()));
+ PSESSION->keyboard = makeShared(m_sState.keyboardMgr->sendCreateVirtualKeyboard(g_pPortalManager->m_sWaylandConnection.seat->resource()));
+
+ const auto& keymap = g_pPortalManager->m_sKeymap;
+ PSESSION->keyboard->sendKeymap(keymap.format, keymap.fd, keymap.size);
+
+ PSESSION->eis = std::make_unique("eisr-" + std::to_string(m_uSessionCounter++));
+ PSESSION->eis->setVirtualPointer(PSESSION->pointer);
+ PSESSION->eis->setVirtualKeyboard(PSESSION->keyboard);
+
+ m_mSessions.emplace(sessionHandle, PSESSION);
+
+ return {0, {}};
+}
+
+dbUasv CRemoteDesktopPortal::onSelectDevices(sdbus::ObjectPath requestHandle, sdbus::ObjectPath sessionHandle, std::string appID,
+ std::unordered_map opts) {
+ return {0, {}};
+}
+
+dbUasv CRemoteDesktopPortal::onStart(sdbus::ObjectPath requestHandle, sdbus::ObjectPath sessionHandle, std::string appID, std::string parentWindow,
+ std::unordered_map opts) {
+ Debug::log(LOG, "[remotedesktop] start request");
+
+ std::unordered_map results;
+ results["devices"] = sdbus::Variant{uint32_t{1 | 2}};
+ results["clipboard_enabled"] = sdbus::Variant{bool(true)};
+
+ std::unordered_map restoreData;
+ results["restore_data"] = sdbus::Variant{sdbus::Struct{"hyprland", 1, sdbus::Variant{restoreData}}};
+ results["persist_mode"] = sdbus::Variant{uint32_t{2}};
+
+ return {0, results};
+}
+
+dbUasv CRemoteDesktopPortal::onNotifyPointerMotion(sdbus::ObjectPath sessionHandle, double dx, double dy, std::unordered_map opts) {
+ const auto PSESSION = m_mSessions[sessionHandle];
+ PSESSION->pointer->sendMotion(0, dx, dy);
+ return {0, {}};
+}
+
+dbUasv CRemoteDesktopPortal::onNotifyPointerMotionAbsolute(sdbus::ObjectPath sessionHandle, unsigned int stream, double x, double y, std::unordered_map opts) {
+ const auto PSESSION = m_mSessions[sessionHandle];
+ PSESSION->pointer->sendMotionAbsolute(0, x, y, 1920, 1080);
+ return {0, {}};
+}
+
+dbUasv CRemoteDesktopPortal::onNotifyPointerButton(sdbus::ObjectPath sessionHandle, int button, unsigned int state, std::unordered_map opts) {
+ const auto PSESSION = m_mSessions[sessionHandle];
+ PSESSION->pointer->sendButton(0, button, state);
+ return {0, {}};
+}
+
+dbUasv CRemoteDesktopPortal::onNotifyPointerAxis(sdbus::ObjectPath sessionHandle, double dx, double dy, std::unordered_map opts) {
+ const auto PSESSION = m_mSessions[sessionHandle];
+ PSESSION->pointer->sendAxis(0, 0, dy);
+ PSESSION->pointer->sendAxis(0, 1, dx);
+ return {0, {}};
+}
+
+dbUasv CRemoteDesktopPortal::onNotifyPointerAxisDiscrete(sdbus::ObjectPath sessionHandle, unsigned int axis, int steps, std::unordered_map opts) {
+ const auto PSESSION = m_mSessions[sessionHandle];
+ PSESSION->pointer->sendAxisDiscrete(1, 0, axis, steps);
+ return {0, {}};
+}
+
+dbUasv CRemoteDesktopPortal::onNotifyKeyboardKeycode(sdbus::ObjectPath sessionHandle, int keycode, unsigned int state, std::unordered_map opts) {
+ const auto PSESSION = m_mSessions[sessionHandle];
+ PSESSION->keyboard->sendKey(1, keycode, state);
+ return {0, {}};
+}
+
+dbUasv CRemoteDesktopPortal::onNotifyKeyboardKeysym(sdbus::ObjectPath sessionHandle, int keysym, unsigned int state, std::unordered_map opts) {
+ const auto PSESSION = m_mSessions[sessionHandle];
+ return {0, {}};
+}
+
+dbUasv CRemoteDesktopPortal::onNotifyTouchDown(sdbus::ObjectPath sessionHandle, unsigned int stream, unsigned int slot, double x, double y,
+ std::unordered_map opts) {
+ const auto PSESSION = m_mSessions[sessionHandle];
+ return {0, {}};
+}
+
+dbUasv CRemoteDesktopPortal::onNotifyTouchMotion(sdbus::ObjectPath sessionHandle, unsigned int stream, unsigned int slot, double x, double y,
+ std::unordered_map opts) {
+ const auto PSESSION = m_mSessions[sessionHandle];
+ return {0, {}};
+}
+
+dbUasv CRemoteDesktopPortal::onNotifyTouchUp(sdbus::ObjectPath sessionHandle, unsigned int slot, std::unordered_map opts) {
+ const auto PSESSION = m_mSessions[sessionHandle];
+ return {0, {}};
+}
+
+sdbus::UnixFd CRemoteDesktopPortal::onConnectToEIS(sdbus::ObjectPath sessionHandle, std::string appID, std::unordered_map opts) {
+ Debug::log(LOG, "[remotedesktop] New ConnectToEIS request: {}:", sessionHandle.c_str());
+ const auto PSESSION = m_mSessions[sessionHandle];
+ if (!PSESSION) return (sdbus::UnixFd)0;
+
+ int sockfd = PSESSION->eis->getFileDescriptor();
+
+ Debug::log(LOG, "[remotedesktop] Connected to the socket. File descriptor: {}", sockfd);
+ return (sdbus::UnixFd)sockfd;
+}
diff --git a/src/portals/RemoteDesktop.hpp b/src/portals/RemoteDesktop.hpp
new file mode 100644
index 0000000..8573127
--- /dev/null
+++ b/src/portals/RemoteDesktop.hpp
@@ -0,0 +1,64 @@
+#pragma once
+
+#include
+#include "wlr-virtual-pointer-unstable-v1.hpp"
+#include "virtual-keyboard-unstable-v1.hpp"
+#include "../shared/Session.hpp"
+#include "../shared/Eis.hpp"
+#include "../dbusDefines.hpp"
+#include
+#include
+
+class CRemoteDesktopPortal {
+ public:
+ CRemoteDesktopPortal();
+ void registerPointer(SP mgr);
+ void registerKeyboard(SP mgr);
+
+ dbUasv onCreateSession(sdbus::ObjectPath requestHandle, sdbus::ObjectPath sessionHandle, std::string appID,
+ std::unordered_map opts);
+ dbUasv onSelectDevices(sdbus::ObjectPath requestHandle, sdbus::ObjectPath sessionHandle, std::string appID,
+ std::unordered_map opts);
+ dbUasv onStart(sdbus::ObjectPath requestHandle, sdbus::ObjectPath sessionHandle, std::string appID, std::string parentWindow,
+ std::unordered_map opts);
+ dbUasv onNotifyPointerMotion(sdbus::ObjectPath sessionHandle, double dx, double dy, std::unordered_map opts);
+ dbUasv onNotifyPointerMotionAbsolute(sdbus::ObjectPath sessionHandle, unsigned int stream, double x, double y, std::unordered_map opts);
+ dbUasv onNotifyPointerButton(sdbus::ObjectPath sessionHandle, int button, unsigned int state, std::unordered_map opts);
+ dbUasv onNotifyPointerAxis(sdbus::ObjectPath sessionHandle, double dx, double dy, std::unordered_map opts);
+ dbUasv onNotifyPointerAxisDiscrete(sdbus::ObjectPath sessionHandle, unsigned int axis, int steps, std::unordered_map opts);
+ dbUasv onNotifyKeyboardKeycode(sdbus::ObjectPath sessionHandle, int keycode, unsigned int state, std::unordered_map opts);
+ dbUasv onNotifyKeyboardKeysym(sdbus::ObjectPath sessionHandle, int keysym, unsigned int state, std::unordered_map opts);
+ dbUasv onNotifyTouchDown(sdbus::ObjectPath sessionHandle, unsigned int stream, unsigned int slot, double x, double y,
+ std::unordered_map opts);
+ dbUasv onNotifyTouchMotion(sdbus::ObjectPath sessionHandle, unsigned int stream, unsigned int slot, double x, double y,
+ std::unordered_map opts);
+ dbUasv onNotifyTouchUp(sdbus::ObjectPath sessionHandle, unsigned int slot, std::unordered_map opts);
+ sdbus::UnixFd onConnectToEIS(sdbus::ObjectPath sessionHandle, std::string appID, std::unordered_map opts);
+
+ struct SSession {
+ std::string appid;
+ sdbus::ObjectPath requestHandle, sessionHandle;
+ std::unique_ptr request;
+ std::unique_ptr session;
+
+ SP pointer;
+ SP keyboard;
+ std::unique_ptr eis;
+ };
+
+ std::unordered_map> m_mSessions;
+
+ private:
+ std::priority_queue, std::greater> m_pqFreeIds;
+
+ struct {
+ SP pointerMgr;
+ SP keyboardMgr;
+ } m_sState;
+
+ std::unique_ptr m_pObject;
+ uint m_uSessionCounter = 0;
+
+ const sdbus::InterfaceName INTERFACE_NAME = sdbus::InterfaceName{"org.freedesktop.impl.portal.RemoteDesktop"};
+ const sdbus::ObjectPath OBJECT_PATH = sdbus::ObjectPath{"/org/freedesktop/portal/desktop"};
+};
diff --git a/src/shared/Eis.cpp b/src/shared/Eis.cpp
index 6032fba..7807c1e 100644
--- a/src/shared/Eis.cpp
+++ b/src/shared/Eis.cpp
@@ -6,12 +6,11 @@
#include
#include
#include
+#include
-EmulatedInputServer::EmulatedInputServer(std::string socketName, Keymap _keymap) {
+EmulatedInputServer::EmulatedInputServer(std::string socketName) {
Debug::log(LOG, "[EIS] Init socket: {}", socketName);
- keymap = _keymap;
-
const char* xdg = getenv("XDG_RUNTIME_DIR");
if (xdg)
socketPath = std::string(xdg) + "/" + socketName;
@@ -61,12 +60,6 @@ int EmulatedInputServer::onEvent(eis_event* e) {
eisClient = eis_event_get_client(e);
Debug::log(LOG, "[EIS] {} client connected: {}", eis_client_is_sender(eisClient) ? "Sender" : "Receiver", eis_client_get_name(eisClient));
- if (eis_client_is_sender(eisClient)) {
- Debug::log(WARN, "[EIS] Unexpected sender client {} connected to input capture session", eis_client_get_name(eisClient));
- eis_client_disconnect(eisClient);
- return 0;
- }
-
if (client.handle) {
Debug::log(WARN, "[EIS] Unexpected additional client {} connected to input capture session", eis_client_get_name(eisClient));
eis_client_disconnect(eisClient);
@@ -80,6 +73,7 @@ int EmulatedInputServer::onEvent(eis_event* e) {
seat = eis_client_new_seat(eisClient, "default");
eis_seat_configure_capability(seat, EIS_DEVICE_CAP_POINTER);
+ eis_seat_configure_capability(seat, EIS_DEVICE_CAP_POINTER_ABSOLUTE);
eis_seat_configure_capability(seat, EIS_DEVICE_CAP_BUTTON);
eis_seat_configure_capability(seat, EIS_DEVICE_CAP_SCROLL);
eis_seat_configure_capability(seat, EIS_DEVICE_CAP_KEYBOARD);
@@ -120,6 +114,121 @@ int EmulatedInputServer::onEvent(eis_event* e) {
} else
Debug::log(WARN, "[EIS] Unknown device to close");
break;
+ case EIS_EVENT_FRAME:
+ if (virtualPointer != nullptr) {
+ virtualPointer->sendFrame();
+ }
+ break;
+ case EIS_EVENT_DEVICE_START_EMULATING:
+ device = eis_event_get_device(e);
+ Debug::log(LOG, "[EIS] Device {} is ready to send events", eis_device_get_name(device));
+ break;
+ case EIS_EVENT_DEVICE_STOP_EMULATING:
+ device = eis_event_get_device(e);
+ Debug::log(LOG, "[EIS] Device {} will no longer send events", eis_device_get_name(device));
+ break;
+ case EIS_EVENT_POINTER_MOTION:
+ if (virtualPointer != nullptr) {
+ virtualPointer->sendMotion(0, eis_event_pointer_get_dx(e), eis_event_pointer_get_dy(e));
+ }
+ break;
+ case EIS_EVENT_POINTER_MOTION_ABSOLUTE:
+ if (virtualPointer != nullptr) {
+ virtualPointer->sendMotionAbsolute(0, eis_event_pointer_get_absolute_x(e), eis_event_pointer_get_absolute_y(e), screenWidth, screenHeight);
+ }
+ break;
+ case EIS_EVENT_BUTTON_BUTTON:
+ if (virtualPointer != nullptr) {
+ virtualPointer->sendButton(0, eis_event_button_get_button(e), eis_event_button_get_is_press(e));
+ }
+ break;
+ case EIS_EVENT_SCROLL_DELTA:
+ if (virtualPointer != nullptr) {
+ virtualPointer->sendAxis(0, 0, eis_event_scroll_get_dy(e));
+ virtualPointer->sendAxis(0, 1, eis_event_scroll_get_dx(e));
+ }
+ break;
+ case EIS_EVENT_SCROLL_STOP:
+ if (virtualPointer != nullptr) {
+ if (eis_event_scroll_get_stop_x(e))
+ virtualPointer->sendAxisStop(0, 1);
+ if (eis_event_scroll_get_stop_y(e))
+ virtualPointer->sendAxisStop(0, 0);
+ }
+ break;
+ case EIS_EVENT_SCROLL_DISCRETE:
+ if (virtualPointer != nullptr) {
+ virtualPointer->sendAxisDiscrete(1, 0, 1, eis_event_scroll_get_discrete_dy(e));
+ virtualPointer->sendAxisDiscrete(1, 1, 1, eis_event_scroll_get_discrete_dx(e));
+ }
+ break;
+ case EIS_EVENT_KEYBOARD_KEY:
+ {
+ if (virtualKeyboard != nullptr) {
+ uint32_t keycode = eis_event_keyboard_get_key(e);
+ bool pressed = eis_event_keyboard_get_key_is_press(e);
+ switch (keycode) {
+ case KEY_LEFTSHIFT:
+ case KEY_RIGHTSHIFT:
+ if (pressed)
+ depressed |= 1;
+ else
+ depressed &= ~(1);
+ break;
+ case KEY_CAPSLOCK:
+ if (pressed) {
+ if (locked & (1 << 1))
+ locked &= ~(1 << 1);
+ else
+ locked |= 1 << 1;
+ }
+ break;
+ case KEY_LEFTCTRL:
+ case KEY_RIGHTCTRL:
+ if (pressed)
+ depressed |= 1 << 2;
+ else
+ depressed &= ~(1 << 2);
+ break;
+ case KEY_LEFTALT:
+ case KEY_RIGHTALT:
+ if (pressed)
+ depressed |= 1 << 3;
+ else
+ depressed &= ~(1 << 3);
+ break;
+ case KEY_NUMLOCK:
+ if (pressed) {
+ if (locked & (1 << 4))
+ locked &= ~(1 << 4);
+ else
+ locked |= 1 << 4;
+ }
+ break;
+ case KEY_LEFTMETA:
+ case KEY_RIGHTMETA:
+ if (pressed)
+ depressed |= 1 << 6;
+ else
+ depressed &= ~(1 << 6);
+ break;
+ case KEY_SCROLLLOCK:
+ if (pressed) {
+ if (locked & (1 << 7))
+ locked &= ~(1 << 7);
+ else
+ locked |= 1 << 7;
+ }
+ break;
+ default:
+ virtualKeyboard->sendModifiers(depressed, latched, locked, 3);
+ virtualKeyboard->sendKey(1, keycode, pressed);
+ break;
+ }
+ }
+ }
+ break;
+
default: return 0;
}
return 0;
@@ -132,6 +241,7 @@ void EmulatedInputServer::ensurePointer(eis_event* event) {
eis_device* pointer = eis_seat_new_device(client.seat);
eis_device_configure_name(pointer, "captured relative pointer");
eis_device_configure_capability(pointer, EIS_DEVICE_CAP_POINTER);
+ eis_device_configure_capability(pointer, EIS_DEVICE_CAP_POINTER_ABSOLUTE);
eis_device_configure_capability(pointer, EIS_DEVICE_CAP_BUTTON);
eis_device_configure_capability(pointer, EIS_DEVICE_CAP_SCROLL);
@@ -140,9 +250,15 @@ void EmulatedInputServer::ensurePointer(eis_event* event) {
eis_region_set_offset(r, o->x, o->y);
eis_region_set_size(r, o->width, o->height);
+ Debug::log(LOG, "[EIS] REGION TME {} {}", o->width, o->height);
eis_region_set_physical_scale(r, o->scale);
eis_region_add(r);
eis_region_unref(r);
+
+ //#FIXME: #TODO: this doesn't work if there are multiple outputs in getAllOutPuts()
+ screenWidth = o->width;
+ screenHeight = o->height;
+
}
eis_device_add(pointer);
diff --git a/src/shared/Eis.hpp b/src/shared/Eis.hpp
index 3af8181..d69b418 100644
--- a/src/shared/Eis.hpp
+++ b/src/shared/Eis.hpp
@@ -1,7 +1,11 @@
#pragma once
-#include
+#include
#include
+#include "wlr-virtual-pointer-unstable-v1.hpp"
+#include "virtual-keyboard-unstable-v1.hpp"
+#include
+#include "../includes.hpp"
struct Keymap {
int32_t fd = 0;
@@ -13,7 +17,7 @@ struct Keymap {
*/
class EmulatedInputServer {
public:
- EmulatedInputServer(std::string socketPath, Keymap keymap);
+ EmulatedInputServer(std::string socketPath);
std::string socketPath;
void startEmulating(int activationId);
@@ -32,6 +36,9 @@ class EmulatedInputServer {
int getFileDescriptor();
+ void setVirtualPointer(SP ptr) {virtualPointer = ptr;}
+ void setVirtualKeyboard(SP kb) {virtualKeyboard = kb; }
+
void stopServer();
private:
@@ -46,6 +53,15 @@ class EmulatedInputServer {
eis_device* keyboard = nullptr;
} client;
+ SP virtualPointer = nullptr;
+ SP virtualKeyboard = nullptr;
+ uint32_t screenWidth = 0;
+ uint32_t screenHeight = 0;
+
+ uint32_t depressed = 0;
+ uint32_t latched = 0;
+ uint32_t locked = 0;
+
Keymap keymap;
int onEvent(eis_event* e);