Skip to content

Commit efccf25

Browse files
authored
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
1 parent 8e15f91 commit efccf25

File tree

5 files changed

+74
-12
lines changed

5 files changed

+74
-12
lines changed

docs/Hyprland.1

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ Show command usage.
3232
.TP
3333
\f[B]-c\f[R], \f[B]--config\f[R]
3434
Specify config file to use.
35+
\f[B]--socket\f[R]
36+
Sets the Wayland socket name (for Wayland socket handover)
37+
\f[B]--wayland-fd\f[R]
38+
Sets the Wayland socket file descriptor (for Wayland socket handover)
3539
.SH BUGS
3640
.TP
3741
Submit bug reports and request features online at:

docs/Hyprland.1.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ OPTIONS
4141
**-c**, **--config**
4242
Specify config file to use.
4343

44+
**--socket**
45+
Sets the Wayland socket name (for Wayland socket handover)
46+
47+
**--wayland-fd**
48+
Sets the Wayland socket file descriptor (for Wayland socket handover)
49+
4450
BUGS
4551
====
4652

src/Compositor.cpp

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <hyprutils/string/String.hpp>
2828
using namespace Hyprutils::String;
2929

30+
#include <fcntl.h>
3031
#include <sys/types.h>
3132
#include <sys/stat.h>
3233
#include <sys/resource.h>
@@ -533,19 +534,28 @@ void CCompositor::prepareFallbackOutput() {
533534
wlr_headless_add_output(headless, 1920, 1080);
534535
}
535536

536-
void CCompositor::startCompositor() {
537+
void CCompositor::startCompositor(std::string socketName, int socketFd) {
537538
initAllSignals();
538539

539-
// get socket, avoid using 0
540-
for (int candidate = 1; candidate <= 32; candidate++) {
541-
const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate));
542-
const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str());
540+
if (!socketName.empty() && socketFd != -1) {
541+
fcntl(socketFd, F_SETFD, FD_CLOEXEC);
542+
const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd);
543543
if (RETVAL >= 0) {
544-
m_szWLDisplaySocket = CANDIDATESTR;
545-
Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL);
546-
break;
547-
} else {
548-
Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate);
544+
m_szWLDisplaySocket = socketName;
545+
Debug::log(LOG, "wl_display_add_socket_fd for {} succeeded with {}", socketName, RETVAL);
546+
} else
547+
Debug::log(WARN, "wl_display_add_socket_fd for {} returned {}: skipping", socketName, RETVAL);
548+
} else {
549+
// get socket, avoid using 0
550+
for (int candidate = 1; candidate <= 32; candidate++) {
551+
const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate));
552+
const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str());
553+
if (RETVAL >= 0) {
554+
m_szWLDisplaySocket = CANDIDATESTR;
555+
Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL);
556+
break;
557+
} else
558+
Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate);
549559
}
550560
}
551561

src/Compositor.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class CCompositor {
7878
std::unordered_map<std::string, uint64_t> m_mMonitorIDMap;
7979

8080
void initServer();
81-
void startCompositor();
81+
void startCompositor(std::string socketName, int socketFd);
8282
void cleanup();
8383
void createLockFile();
8484
void removeLockFile();

src/main.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "config/ConfigManager.hpp"
55
#include "init/initHelpers.hpp"
66

7+
#include <fcntl.h>
78
#include <iostream>
89
#include <iterator>
910
#include <vector>
@@ -16,6 +17,8 @@ void help() {
1617
std::cout << "\nArguments:\n";
1718
std::cout << " --help -h - Show this message again\n";
1819
std::cout << " --config FILE -c FILE - Specify config file to use\n";
20+
std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n";
21+
std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n";
1922
std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n";
2023
}
2124

@@ -37,6 +40,8 @@ int main(int argc, char** argv) {
3740

3841
// parse some args
3942
std::string configPath;
43+
std::string socketName;
44+
int socketFd = -1;
4045
bool ignoreSudo = false;
4146

4247
std::vector<std::string> args{argv + 1, argv + argc};
@@ -46,6 +51,36 @@ int main(int argc, char** argv) {
4651
std::cout << "[ WARNING ] Running Hyprland with superuser privileges might damage your system\n";
4752

4853
ignoreSudo = true;
54+
} else if (it->compare("--socket") == 0) {
55+
if (std::next(it) == args.end()) {
56+
help();
57+
58+
return 1;
59+
}
60+
61+
socketName = *std::next(it);
62+
it++;
63+
} else if (it->compare("--wayland-fd") == 0) {
64+
if (std::next(it) == args.end()) {
65+
help();
66+
67+
return 1;
68+
}
69+
70+
try {
71+
socketFd = std::stoi(std::next(it)->c_str());
72+
73+
// check if socketFd is a valid file descriptor
74+
if (fcntl(socketFd, F_GETFD) == -1)
75+
throw std::exception();
76+
} catch (...) {
77+
std::cerr << "[ ERROR ] Invalid Wayland FD!\n";
78+
help();
79+
80+
return 1;
81+
}
82+
83+
it++;
4984
} else if (it->compare("-c") == 0 || it->compare("--config") == 0) {
5085
if (std::next(it) == args.end()) {
5186
help();
@@ -93,6 +128,13 @@ int main(int argc, char** argv) {
93128
std::cout << "Superuser privileges check is omitted. I hope you know what you're doing.\n";
94129
}
95130

131+
if (socketName.empty() ^ (socketFd == -1)) {
132+
std::cerr << "[ ERROR ] Hyprland was launched with only one of --socket and --wayland-fd.\n";
133+
std::cerr << " Hint: Pass both --socket and --wayland-fd to perform Wayland socket handover.\n";
134+
135+
return 1;
136+
}
137+
96138
std::cout << "Welcome to Hyprland!\n";
97139

98140
// let's init the compositor.
@@ -113,7 +155,7 @@ int main(int argc, char** argv) {
113155
Debug::log(LOG, "Hyprland init finished.");
114156

115157
// If all's good to go, start.
116-
g_pCompositor->startCompositor();
158+
g_pCompositor->startCompositor(socketName, socketFd);
117159

118160
g_pCompositor->m_bIsShuttingDown = true;
119161

0 commit comments

Comments
 (0)