Skip to content

Commit

Permalink
compositor: implement wayland socket handover (#6930)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Ferdi265 authored Jul 19, 2024
1 parent 8e15f91 commit efccf25
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 12 deletions.
4 changes: 4 additions & 0 deletions docs/Hyprland.1
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions docs/Hyprland.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
====

Expand Down
30 changes: 20 additions & 10 deletions src/Compositor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
Expand Down Expand Up @@ -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);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Compositor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class CCompositor {
std::unordered_map<std::string, uint64_t> m_mMonitorIDMap;

void initServer();
void startCompositor();
void startCompositor(std::string socketName, int socketFd);
void cleanup();
void createLockFile();
void removeLockFile();
Expand Down
44 changes: 43 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "config/ConfigManager.hpp"
#include "init/initHelpers.hpp"

#include <fcntl.h>
#include <iostream>
#include <iterator>
#include <vector>
Expand All @@ -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";
}

Expand All @@ -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<std::string> args{argv + 1, argv + argc};
Expand All @@ -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();
Expand Down Expand Up @@ -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.
Expand All @@ -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;

Expand Down

0 comments on commit efccf25

Please sign in to comment.