Skip to content

Commit 0d8d425

Browse files
authored
Merge pull request #3945 from zjeffer/fix/zjeffer/hyprland-ipc
Hyprland IPC improvements
2 parents d098dbb + 37c6cd4 commit 0d8d425

File tree

12 files changed

+192
-159
lines changed

12 files changed

+192
-159
lines changed

include/modules/hyprland/backend.hpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
#include <filesystem>
44
#include <list>
5-
#include <memory>
65
#include <mutex>
76
#include <string>
7+
#include <thread>
88
#include <utility>
99

1010
#include "util/json.hpp"
@@ -19,7 +19,9 @@ class EventHandler {
1919

2020
class IPC {
2121
public:
22-
IPC() { startIPC(); }
22+
IPC();
23+
~IPC();
24+
static IPC& inst();
2325

2426
void registerForIPC(const std::string& ev, EventHandler* ev_handler);
2527
void unregisterForIPC(EventHandler* handler);
@@ -32,14 +34,16 @@ class IPC {
3234
static std::filesystem::path socketFolder_;
3335

3436
private:
35-
void startIPC();
37+
void socketListener();
3638
void parseIPC(const std::string&);
3739

40+
std::thread ipcThread_;
3841
std::mutex callbackMutex_;
3942
util::JsonParser parser_;
4043
std::list<std::pair<std::string, EventHandler*>> callbacks_;
44+
int socketfd_; // the hyprland socket file descriptor
45+
bool running_ = true;
4146
};
4247

43-
inline std::unique_ptr<IPC> gIPC;
4448
inline bool modulesReady = false;
4549
}; // namespace waybar::modules::hyprland

include/modules/hyprland/language.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class Language : public waybar::ALabel, public EventHandler {
3737
util::JsonParser parser_;
3838

3939
Layout layout_;
40+
41+
IPC& m_ipc;
4042
};
4143

4244
} // namespace waybar::modules::hyprland

include/modules/hyprland/submap.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class Submap : public waybar::ALabel, public EventHandler {
2828
std::string submap_;
2929
bool always_on_ = false;
3030
std::string default_submap_ = "Default";
31+
32+
IPC& m_ipc;
3133
};
3234

3335
} // namespace waybar::modules::hyprland

include/modules/hyprland/window.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
6060
bool swallowing_;
6161
bool fullscreen_;
6262
bool focused_;
63+
64+
IPC& m_ipc;
6365
};
6466

6567
} // namespace waybar::modules::hyprland

include/modules/hyprland/workspace.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class Workspace {
8383
Gtk::Button m_button;
8484
Gtk::Box m_content;
8585
Gtk::Label m_label;
86+
IPC& m_ipc;
8687
};
8788

8889
} // namespace waybar::modules::hyprland

include/modules/hyprland/workspaces.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ class Workspaces : public AModule, public EventHandler {
150150
std::mutex m_mutex;
151151
const Bar& m_bar;
152152
Gtk::Box m_box;
153+
IPC& m_ipc;
153154
};
154155

155156
} // namespace waybar::modules::hyprland

src/modules/hyprland/backend.cpp

Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
#include <filesystem>
1313
#include <string>
14-
#include <thread>
1514

1615
namespace waybar::modules::hyprland {
1716

@@ -44,71 +43,96 @@ std::filesystem::path IPC::getSocketFolder(const char* instanceSig) {
4443
return socketFolder_;
4544
}
4645

47-
void IPC::startIPC() {
46+
IPC::IPC() {
4847
// will start IPC and relay events to parseIPC
48+
ipcThread_ = std::thread([this]() { socketListener(); });
49+
}
4950

50-
std::thread([&]() {
51-
// check for hyprland
52-
const char* his = getenv("HYPRLAND_INSTANCE_SIGNATURE");
53-
54-
if (his == nullptr) {
55-
spdlog::warn("Hyprland is not running, Hyprland IPC will not be available.");
56-
return;
51+
IPC::~IPC() {
52+
running_ = false;
53+
spdlog::info("Hyprland IPC stopping...");
54+
if (socketfd_ != -1) {
55+
spdlog::trace("Shutting down socket");
56+
if (shutdown(socketfd_, SHUT_RDWR) == -1) {
57+
spdlog::error("Hyprland IPC: Couldn't shutdown socket");
58+
}
59+
spdlog::trace("Closing socket");
60+
if (close(socketfd_) == -1) {
61+
spdlog::error("Hyprland IPC: Couldn't close socket");
5762
}
63+
}
64+
ipcThread_.join();
65+
}
5866

59-
if (!modulesReady) return;
67+
IPC& IPC::inst() {
68+
static IPC ipc;
69+
return ipc;
70+
}
6071

61-
spdlog::info("Hyprland IPC starting");
72+
void IPC::socketListener() {
73+
// check for hyprland
74+
const char* his = getenv("HYPRLAND_INSTANCE_SIGNATURE");
6275

63-
struct sockaddr_un addr;
64-
int socketfd = socket(AF_UNIX, SOCK_STREAM, 0);
76+
if (his == nullptr) {
77+
spdlog::warn("Hyprland is not running, Hyprland IPC will not be available.");
78+
return;
79+
}
6580

66-
if (socketfd == -1) {
67-
spdlog::error("Hyprland IPC: socketfd failed");
68-
return;
69-
}
81+
if (!modulesReady) return;
7082

71-
addr.sun_family = AF_UNIX;
83+
spdlog::info("Hyprland IPC starting");
7284

73-
auto socketPath = IPC::getSocketFolder(his) / ".socket2.sock";
74-
strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1);
85+
struct sockaddr_un addr;
86+
socketfd_ = socket(AF_UNIX, SOCK_STREAM, 0);
7587

76-
addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
88+
if (socketfd_ == -1) {
89+
spdlog::error("Hyprland IPC: socketfd failed");
90+
return;
91+
}
7792

78-
int l = sizeof(struct sockaddr_un);
93+
addr.sun_family = AF_UNIX;
7994

80-
if (connect(socketfd, (struct sockaddr*)&addr, l) == -1) {
81-
spdlog::error("Hyprland IPC: Unable to connect?");
82-
return;
83-
}
95+
auto socketPath = IPC::getSocketFolder(his) / ".socket2.sock";
96+
strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1);
8497

85-
auto* file = fdopen(socketfd, "r");
98+
addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
8699

87-
while (true) {
88-
std::array<char, 1024> buffer; // Hyprland socket2 events are max 1024 bytes
100+
int l = sizeof(struct sockaddr_un);
89101

90-
auto* receivedCharPtr = fgets(buffer.data(), buffer.size(), file);
102+
if (connect(socketfd_, (struct sockaddr*)&addr, l) == -1) {
103+
spdlog::error("Hyprland IPC: Unable to connect?");
104+
return;
105+
}
106+
auto* file = fdopen(socketfd_, "r");
107+
if (file == nullptr) {
108+
spdlog::error("Hyprland IPC: Couldn't open file descriptor");
109+
return;
110+
}
111+
while (running_) {
112+
std::array<char, 1024> buffer; // Hyprland socket2 events are max 1024 bytes
91113

92-
if (receivedCharPtr == nullptr) {
93-
std::this_thread::sleep_for(std::chrono::milliseconds(1));
94-
continue;
95-
}
114+
auto* receivedCharPtr = fgets(buffer.data(), buffer.size(), file);
96115

97-
std::string messageReceived(buffer.data());
98-
messageReceived = messageReceived.substr(0, messageReceived.find_first_of('\n'));
99-
spdlog::debug("hyprland IPC received {}", messageReceived);
116+
if (receivedCharPtr == nullptr) {
117+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
118+
continue;
119+
}
100120

101-
try {
102-
parseIPC(messageReceived);
103-
} catch (std::exception& e) {
104-
spdlog::warn("Failed to parse IPC message: {}, reason: {}", messageReceived, e.what());
105-
} catch (...) {
106-
throw;
107-
}
121+
std::string messageReceived(buffer.data());
122+
messageReceived = messageReceived.substr(0, messageReceived.find_first_of('\n'));
123+
spdlog::debug("hyprland IPC received {}", messageReceived);
108124

109-
std::this_thread::sleep_for(std::chrono::milliseconds(1));
125+
try {
126+
parseIPC(messageReceived);
127+
} catch (std::exception& e) {
128+
spdlog::warn("Failed to parse IPC message: {}, reason: {}", messageReceived, e.what());
129+
} catch (...) {
130+
throw;
110131
}
111-
}).detach();
132+
133+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
134+
}
135+
spdlog::debug("Hyprland IPC stopped");
112136
}
113137

114138
void IPC::parseIPC(const std::string& ev) {

src/modules/hyprland/language.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,21 @@
1010
namespace waybar::modules::hyprland {
1111

1212
Language::Language(const std::string& id, const Bar& bar, const Json::Value& config)
13-
: ALabel(config, "language", id, "{}", 0, true), bar_(bar) {
13+
: ALabel(config, "language", id, "{}", 0, true), bar_(bar), m_ipc(IPC::inst()) {
1414
modulesReady = true;
1515

16-
if (!gIPC) {
17-
gIPC = std::make_unique<IPC>();
18-
}
19-
2016
// get the active layout when open
2117
initLanguage();
2218

2319
label_.hide();
2420
update();
2521

2622
// register for hyprland ipc
27-
gIPC->registerForIPC("activelayout", this);
23+
m_ipc.registerForIPC("activelayout", this);
2824
}
2925

3026
Language::~Language() {
31-
gIPC->unregisterForIPC(this);
27+
m_ipc.unregisterForIPC(this);
3228
// wait for possible event handler to finish
3329
std::lock_guard<std::mutex> lg(mutex_);
3430
}
@@ -85,7 +81,7 @@ void Language::onEvent(const std::string& ev) {
8581
}
8682

8783
void Language::initLanguage() {
88-
const auto inputDevices = gIPC->getSocket1Reply("devices");
84+
const auto inputDevices = m_ipc.getSocket1Reply("devices");
8985

9086
const auto kbName = config_["keyboard-name"].asString();
9187

src/modules/hyprland/submap.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,11 @@
77
namespace waybar::modules::hyprland {
88

99
Submap::Submap(const std::string& id, const Bar& bar, const Json::Value& config)
10-
: ALabel(config, "submap", id, "{}", 0, true), bar_(bar) {
10+
: ALabel(config, "submap", id, "{}", 0, true), bar_(bar), m_ipc(IPC::inst()) {
1111
modulesReady = true;
1212

1313
parseConfig(config);
1414

15-
if (!gIPC) {
16-
gIPC = std::make_unique<IPC>();
17-
}
18-
1915
label_.hide();
2016
ALabel::update();
2117

@@ -27,12 +23,12 @@ Submap::Submap(const std::string& id, const Bar& bar, const Json::Value& config)
2723
}
2824

2925
// register for hyprland ipc
30-
gIPC->registerForIPC("submap", this);
26+
m_ipc.registerForIPC("submap", this);
3127
dp.emit();
3228
}
3329

3430
Submap::~Submap() {
35-
gIPC->unregisterForIPC(this);
31+
m_ipc.unregisterForIPC(this);
3632
// wait for possible event handler to finish
3733
std::lock_guard<std::mutex> lg(mutex_);
3834
}

0 commit comments

Comments
 (0)