From efccf25fcc72b416c63ff540703d9f061f39a7f2 Mon Sep 17 00:00:00 2001 From: Ferdinand Bachmann Date: Sat, 20 Jul 2024 00:37:20 +0200 Subject: [PATCH] compositor: implement wayland socket handover (#6930) * compositor: implement wayland socket handover This commit implements the compositor side of the Wayland socket handover protocol as described in the [KDE Wiki]. The CLI options are chosen so that they are compatible with Kwin. [KDE Wiki]: https://invent.kde.org/plasma/kwin/-/wikis/Restarting * main: verify that --wayland-fd is a valid file descriptor * main: fail if only one of --socket and --wayland-fd is passed --- docs/Hyprland.1 | 4 ++++ docs/Hyprland.1.rst | 6 ++++++ src/Compositor.cpp | 30 ++++++++++++++++++++---------- src/Compositor.hpp | 2 +- src/main.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 74 insertions(+), 12 deletions(-) diff --git a/docs/Hyprland.1 b/docs/Hyprland.1 index f43d2c5d..5ef24fd5 100644 --- a/docs/Hyprland.1 +++ b/docs/Hyprland.1 @@ -32,6 +32,10 @@ Show command usage. .TP \f[B]-c\f[R], \f[B]--config\f[R] Specify config file to use. +\f[B]--socket\f[R] +Sets the Wayland socket name (for Wayland socket handover) +\f[B]--wayland-fd\f[R] +Sets the Wayland socket file descriptor (for Wayland socket handover) .SH BUGS .TP Submit bug reports and request features online at: diff --git a/docs/Hyprland.1.rst b/docs/Hyprland.1.rst index 54126501..c73b4343 100644 --- a/docs/Hyprland.1.rst +++ b/docs/Hyprland.1.rst @@ -41,6 +41,12 @@ OPTIONS **-c**, **--config** Specify config file to use. +**--socket** + Sets the Wayland socket name (for Wayland socket handover) + +**--wayland-fd** + Sets the Wayland socket file descriptor (for Wayland socket handover) + BUGS ==== diff --git a/src/Compositor.cpp b/src/Compositor.cpp index d1c51075..7ffccf36 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -27,6 +27,7 @@ #include using namespace Hyprutils::String; +#include #include #include #include @@ -533,19 +534,28 @@ void CCompositor::prepareFallbackOutput() { wlr_headless_add_output(headless, 1920, 1080); } -void CCompositor::startCompositor() { +void CCompositor::startCompositor(std::string socketName, int socketFd) { initAllSignals(); - // get socket, avoid using 0 - for (int candidate = 1; candidate <= 32; candidate++) { - const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate)); - const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str()); + if (!socketName.empty() && socketFd != -1) { + fcntl(socketFd, F_SETFD, FD_CLOEXEC); + const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd); if (RETVAL >= 0) { - m_szWLDisplaySocket = CANDIDATESTR; - Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL); - break; - } else { - Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate); + m_szWLDisplaySocket = socketName; + Debug::log(LOG, "wl_display_add_socket_fd for {} succeeded with {}", socketName, RETVAL); + } else + Debug::log(WARN, "wl_display_add_socket_fd for {} returned {}: skipping", socketName, RETVAL); + } else { + // get socket, avoid using 0 + for (int candidate = 1; candidate <= 32; candidate++) { + const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate)); + const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str()); + if (RETVAL >= 0) { + m_szWLDisplaySocket = CANDIDATESTR; + Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL); + break; + } else + Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate); } } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 17db2c8b..4aec323f 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -78,7 +78,7 @@ class CCompositor { std::unordered_map m_mMonitorIDMap; void initServer(); - void startCompositor(); + void startCompositor(std::string socketName, int socketFd); void cleanup(); void createLockFile(); void removeLockFile(); diff --git a/src/main.cpp b/src/main.cpp index 7e6fee02..1ac3ab8b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include "config/ConfigManager.hpp" #include "init/initHelpers.hpp" +#include #include #include #include @@ -16,6 +17,8 @@ void help() { std::cout << "\nArguments:\n"; std::cout << " --help -h - Show this message again\n"; std::cout << " --config FILE -c FILE - Specify config file to use\n"; + std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n"; + std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n"; std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; } @@ -37,6 +40,8 @@ int main(int argc, char** argv) { // parse some args std::string configPath; + std::string socketName; + int socketFd = -1; bool ignoreSudo = false; std::vector args{argv + 1, argv + argc}; @@ -46,6 +51,36 @@ int main(int argc, char** argv) { std::cout << "[ WARNING ] Running Hyprland with superuser privileges might damage your system\n"; ignoreSudo = true; + } else if (it->compare("--socket") == 0) { + if (std::next(it) == args.end()) { + help(); + + return 1; + } + + socketName = *std::next(it); + it++; + } else if (it->compare("--wayland-fd") == 0) { + if (std::next(it) == args.end()) { + help(); + + return 1; + } + + try { + socketFd = std::stoi(std::next(it)->c_str()); + + // check if socketFd is a valid file descriptor + if (fcntl(socketFd, F_GETFD) == -1) + throw std::exception(); + } catch (...) { + std::cerr << "[ ERROR ] Invalid Wayland FD!\n"; + help(); + + return 1; + } + + it++; } else if (it->compare("-c") == 0 || it->compare("--config") == 0) { if (std::next(it) == args.end()) { help(); @@ -93,6 +128,13 @@ int main(int argc, char** argv) { std::cout << "Superuser privileges check is omitted. I hope you know what you're doing.\n"; } + if (socketName.empty() ^ (socketFd == -1)) { + std::cerr << "[ ERROR ] Hyprland was launched with only one of --socket and --wayland-fd.\n"; + std::cerr << " Hint: Pass both --socket and --wayland-fd to perform Wayland socket handover.\n"; + + return 1; + } + std::cout << "Welcome to Hyprland!\n"; // let's init the compositor. @@ -113,7 +155,7 @@ int main(int argc, char** argv) { Debug::log(LOG, "Hyprland init finished."); // If all's good to go, start. - g_pCompositor->startCompositor(); + g_pCompositor->startCompositor(socketName, socketFd); g_pCompositor->m_bIsShuttingDown = true;